diff options
author | Tang Chen <tangchen@cn.fujitsu.com> | 2014-02-06 15:04:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-02-06 16:48:51 -0500 |
commit | 7bc35fdde6724549a0239b71e08b9f33d8bf2bfb (patch) | |
tree | 27bef5374ec3d9f888feba0b10381dba0481bc21 /arch | |
parent | 017c217a26e9bf6948482f751b30d0507e30a7d0 (diff) |
arch/x86/mm/numa.c: fix array index overflow when synchronizing nid to memblock.reserved.
The following path will cause array out of bound.
memblock_add_region() will always set nid in memblock.reserved to
MAX_NUMNODES. In numa_register_memblks(), after we set all nid to
correct valus in memblock.reserved, we called setup_node_data(), and
used memblock_alloc_nid() to allocate memory, with nid set to
MAX_NUMNODES.
The nodemask_t type can be seen as a bit array. And the index is 0 ~
MAX_NUMNODES-1.
After that, when we call node_set() in numa_clear_kernel_node_hotplug(),
the nodemask_t got an index of value MAX_NUMNODES, which is out of [0 ~
MAX_NUMNODES-1].
See below:
numa_init()
|---> numa_register_memblks()
| |---> memblock_set_node(memory) set correct nid in memblock.memory
| |---> memblock_set_node(reserved) set correct nid in memblock.reserved
| |......
| |---> setup_node_data()
| |---> memblock_alloc_nid() here, nid is set to MAX_NUMNODES (1024)
|......
|---> numa_clear_kernel_node_hotplug()
|---> node_set() here, we have an index 1024, and overflowed
This patch moves nid setting to numa_clear_kernel_node_hotplug() to fix
this problem.
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Tested-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
Reported-by: Dave Jones <davej@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Tested-by: Dave Jones <davej@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/mm/numa.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 45ec9d72b6dd..27aa0455fab3 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c | |||
@@ -493,14 +493,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) | |||
493 | struct numa_memblk *mb = &mi->blk[i]; | 493 | struct numa_memblk *mb = &mi->blk[i]; |
494 | memblock_set_node(mb->start, mb->end - mb->start, | 494 | memblock_set_node(mb->start, mb->end - mb->start, |
495 | &memblock.memory, mb->nid); | 495 | &memblock.memory, mb->nid); |
496 | |||
497 | /* | ||
498 | * At this time, all memory regions reserved by memblock are | ||
499 | * used by the kernel. Set the nid in memblock.reserved will | ||
500 | * mark out all the nodes the kernel resides in. | ||
501 | */ | ||
502 | memblock_set_node(mb->start, mb->end - mb->start, | ||
503 | &memblock.reserved, mb->nid); | ||
504 | } | 496 | } |
505 | 497 | ||
506 | /* | 498 | /* |
@@ -569,6 +561,17 @@ static void __init numa_clear_kernel_node_hotplug(void) | |||
569 | unsigned long start, end; | 561 | unsigned long start, end; |
570 | struct memblock_type *type = &memblock.reserved; | 562 | struct memblock_type *type = &memblock.reserved; |
571 | 563 | ||
564 | /* | ||
565 | * At this time, all memory regions reserved by memblock are | ||
566 | * used by the kernel. Set the nid in memblock.reserved will | ||
567 | * mark out all the nodes the kernel resides in. | ||
568 | */ | ||
569 | for (i = 0; i < numa_meminfo.nr_blks; i++) { | ||
570 | struct numa_memblk *mb = &numa_meminfo.blk[i]; | ||
571 | memblock_set_node(mb->start, mb->end - mb->start, | ||
572 | &memblock.reserved, mb->nid); | ||
573 | } | ||
574 | |||
572 | /* Mark all kernel nodes. */ | 575 | /* Mark all kernel nodes. */ |
573 | for (i = 0; i < type->cnt; i++) | 576 | for (i = 0; i < type->cnt; i++) |
574 | node_set(type->regions[i].nid, numa_kernel_nodes); | 577 | node_set(type->regions[i].nid, numa_kernel_nodes); |