Skip to content

Commit 8ce41b0

Browse files
tujinjiang11akpm00
authored andcommitted
mm: fix NULL pointer dereference in alloc_pages_bulk_noprof
We triggered a NULL pointer dereference for ac.preferred_zoneref->zone in alloc_pages_bulk_noprof() when the task is migrated between cpusets. When cpuset is enabled, in prepare_alloc_pages(), ac->nodemask may be &current->mems_allowed. when first_zones_zonelist() is called to find preferred_zoneref, the ac->nodemask may be modified concurrently if the task is migrated between different cpusets. Assuming we have 2 NUMA Node, when traversing Node1 in ac->zonelist, the nodemask is 2, and when traversing Node2 in ac->zonelist, the nodemask is 1. As a result, the ac->preferred_zoneref points to NULL zone. In alloc_pages_bulk_noprof(), for_each_zone_zonelist_nodemask() finds a allowable zone and calls zonelist_node_idx(ac.preferred_zoneref), leading to NULL pointer dereference. __alloc_pages_noprof() fixes this issue by checking NULL pointer in commit ea57485 ("mm, page_alloc: fix check for NULL preferred_zone") and commit df76cee ("mm, page_alloc: remove redundant checks from alloc fastpath"). To fix it, check NULL pointer for preferred_zoneref->zone. Link: https://lkml.kernel.org/r/[email protected] Fixes: 387ba26 ("mm/page_alloc: add a bulk page allocator") Signed-off-by: Jinjiang Tu <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: Alexander Lobakin <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Kefeng Wang <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Nanyong Sun <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 0740e54 commit 8ce41b0

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

mm/page_alloc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4607,7 +4607,8 @@ unsigned long alloc_pages_bulk_noprof(gfp_t gfp, int preferred_nid,
46074607
gfp = alloc_gfp;
46084608

46094609
/* Find an allowed local zone that meets the low watermark. */
4610-
for_each_zone_zonelist_nodemask(zone, z, ac.zonelist, ac.highest_zoneidx, ac.nodemask) {
4610+
z = ac.preferred_zoneref;
4611+
for_next_zone_zonelist_nodemask(zone, z, ac.highest_zoneidx, ac.nodemask) {
46114612
unsigned long mark;
46124613

46134614
if (cpusets_enabled() && (alloc_flags & ALLOC_CPUSET) &&

0 commit comments

Comments
 (0)