aboutsummaryrefslogtreecommitdiffstats
path: root/mm/sparse.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-04-15 19:40:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-15 22:30:19 -0400
commitbead9a3abd15710b0bdfd418daef606722d86282 (patch)
tree7557956e8dfe027c0ecf2f2ed759169a4e02a266 /mm/sparse.c
parentcf39cc3b56bc4a562db6242d3069f65034ec7549 (diff)
mm: sparsemem memory_present() fix
Fix memory corruption and crash on 32-bit x86 systems. If a !PAE x86 kernel is booted on a 32-bit system with more than 4GB of RAM, then we call memory_present() with a start/end that goes outside the scope of MAX_PHYSMEM_BITS. That causes this loop to happily walk over the limit of the sparse memory section map: for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { unsigned long section = pfn_to_section_nr(pfn); struct mem_section *ms; sparse_index_init(section, nid); set_section_nid(section, nid); ms = __nr_to_section(section); if (!ms->section_mem_map) ms->section_mem_map = sparse_encode_early_nid(nid) | SECTION_MARKED_PRESENT; 'ms' will be out of bounds and we'll corrupt a small amount of memory by encoding the node ID and writing SECTION_MARKED_PRESENT (==0x1) over it. The corruption might happen when encoding a non-zero node ID, or due to the SECTION_MARKED_PRESENT which is 0x1: mmzone.h:#define SECTION_MARKED_PRESENT (1UL<<0) The fix is to sanity check anything the architecture passes to sparsemem. This bug seems to be rather old (as old as sparsemem support itself), but the exact incarnation depended on random details like configs, which made this bug more prominent in v2.6.25-to-be. An additional enhancement might be to print a warning about ignored or trimmed memory ranges. Signed-off-by: Ingo Molnar <mingo@elte.hu> Tested-by: Christoph Lameter <clameter@sgi.com> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Nick Piggin <npiggin@suse.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Rafael J. Wysocki <rjw@sisk.pl> Cc: Yinghai Lu <Yinghai.Lu@sun.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/sparse.c')
-rw-r--r--mm/sparse.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/mm/sparse.c b/mm/sparse.c
index f6a43c09c322..98d6b39c3472 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -149,8 +149,18 @@ static inline int sparse_early_nid(struct mem_section *section)
149/* Record a memory area against a node. */ 149/* Record a memory area against a node. */
150void __init memory_present(int nid, unsigned long start, unsigned long end) 150void __init memory_present(int nid, unsigned long start, unsigned long end)
151{ 151{
152 unsigned long max_arch_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT);
152 unsigned long pfn; 153 unsigned long pfn;
153 154
155 /*
156 * Sanity checks - do not allow an architecture to pass
157 * in larger pfns than the maximum scope of sparsemem:
158 */
159 if (start >= max_arch_pfn)
160 return;
161 if (end >= max_arch_pfn)
162 end = max_arch_pfn;
163
154 start &= PAGE_SECTION_MASK; 164 start &= PAGE_SECTION_MASK;
155 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) { 165 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
156 unsigned long section = pfn_to_section_nr(pfn); 166 unsigned long section = pfn_to_section_nr(pfn);