From b8b6e4c453929596b630fa1cca1ee26a532a2ab4 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 1 Nov 2011 13:35:12 -0700 Subject: Fix NULL deref in balance_pgdat() Be careful not to unconditionally clear the PF_MEMALLOC bit in the task structure. It may have already been set when entering kv_alloc() in which case it must remain set on exit. In particular the kswapd thread will have PF_MEMALLOC set in order to prevent it from entering direct reclaim. By clearing it we allow the following NULL deref to potentially occur. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] balance_pgdat+0x25b/0x4ff Signed-off-by: Brian Behlendorf Closes ZFS issue #287 --- module/spl/spl-kmem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'module/spl') diff --git a/module/spl/spl-kmem.c b/module/spl/spl-kmem.c index db009614f..b3c054a95 100644 --- a/module/spl/spl-kmem.c +++ b/module/spl/spl-kmem.c @@ -855,14 +855,17 @@ kv_alloc(spl_kmem_cache_t *skc, int size, int flags) * been filed at kernel.org to track the issue. * * https://bugzilla.kernel.org/show_bug.cgi?id=30702 + * + * NOTE: Only set PF_MEMALLOC if it's not already set, and + * then only clear it when we were the one who set it. */ - if (!(flags & __GFP_FS)) + if (!(flags & __GFP_FS) && !(current->flags & PF_MEMALLOC)) { current->flags |= PF_MEMALLOC; - - ptr = __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL); - - if (!(flags & __GFP_FS)) + ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL); current->flags &= ~PF_MEMALLOC; + } else { + ptr = __vmalloc(size, flags|__GFP_HIGHMEM, PAGE_KERNEL); + } } /* Resulting allocated memory will be page aligned */ -- cgit v1.2.3