]> granicus.if.org Git - spl/commitdiff
Fix NULL deref in balance_pgdat()
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 1 Nov 2011 20:35:12 +0000 (13:35 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 3 Nov 2011 16:50:22 +0000 (09:50 -0700)
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: [<ffffffff8109c7ab>] balance_pgdat+0x25b/0x4ff

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes ZFS issue #287

module/spl/spl-kmem.c

index db009614f1f9b942c94d4156ef66ed8f5dbb84de..b3c054a958af74976aa2ac6fcbc7ad29a352d711 100644 (file)
@@ -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 */