Skip to content

Commit 38dfac8

Browse files
steinbeck65torvalds
authored andcommitted
vmcore: prevent PT_NOTE p_memsz overflow during header update
Currently, update_note_header_size_elf64() and update_note_header_size_elf32() will add the size of a PT_NOTE entry to real_sz even if that causes real_sz to exceeds max_sz. This patch corrects the while loop logic in those routines to ensure that does not happen and prints a warning if a PT_NOTE entry is dropped. If zero PT_NOTE entries are found or this condition is encountered because the only entry was dropped, a warning is printed and an error is returned. One possible negative side effect of exceeding the max_sz limit is an allocation failure in merge_note_headers_elf64() or merge_note_headers_elf32() which would produce console output such as the following while booting the crash kernel. vmalloc: allocation failure: 14076997632 bytes swapper/0: page allocation failure: order:0, mode:0x80d2 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-gbp1 torvalds#7 Call Trace: dump_stack+0x19/0x1b warn_alloc_failed+0xf0/0x160 __vmalloc_node_range+0x19e/0x250 vmalloc_user+0x4c/0x70 merge_note_headers_elf64.constprop.9+0x116/0x24a vmcore_init+0x2d4/0x76c do_one_initcall+0xe2/0x190 kernel_init_freeable+0x17c/0x207 kernel_init+0xe/0x180 ret_from_fork+0x7c/0xb0 Kdump: vmcore not initialized kdump: dump target is /dev/sda4 kdump: saving to /sysroot//var/crash/127.0.0.1-2014.01.28-13:58:52/ kdump: saving vmcore-dmesg.txt Cannot open /proc/vmcore: No such file or directory kdump: saving vmcore-dmesg.txt failed kdump: saving vmcore kdump: saving vmcore failed This type of failure has been seen on a four socket prototype system with certain memory configurations. Most PT_NOTE sections have a single entry similar to: n_namesz = 0x5 n_descsz = 0x150 n_type = 0x1 Occasionally, a second entry is encountered with very large n_namesz and n_descsz sizes: n_namesz = 0x80000008 n_descsz = 0x510ae163 n_type = 0x80000008 Not yet sure of the source of these extra entries, they seem bogus, but they shouldn't cause crash dump to fail. Signed-off-by: Greg Pearson <greg.pearson@hp.com> Acked-by: Vivek Goyal <vgoyal@redhat.com> Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com> Cc: Michael Holzheu <holzheu@linux.vnet.ibm.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a3eb7fb commit 38dfac8

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

fs/proc/vmcore.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,17 +468,24 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
468468
return rc;
469469
}
470470
nhdr_ptr = notes_section;
471-
while (real_sz < max_sz) {
472-
if (nhdr_ptr->n_namesz == 0)
473-
break;
471+
while (nhdr_ptr->n_namesz != 0) {
474472
sz = sizeof(Elf64_Nhdr) +
475473
((nhdr_ptr->n_namesz + 3) & ~3) +
476474
((nhdr_ptr->n_descsz + 3) & ~3);
475+
if ((real_sz + sz) > max_sz) {
476+
pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
477+
nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
478+
break;
479+
}
477480
real_sz += sz;
478481
nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
479482
}
480483
kfree(notes_section);
481484
phdr_ptr->p_memsz = real_sz;
485+
if (real_sz == 0) {
486+
pr_warn("Warning: Zero PT_NOTE entries found\n");
487+
return -EINVAL;
488+
}
482489
}
483490

484491
return 0;
@@ -648,17 +655,24 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
648655
return rc;
649656
}
650657
nhdr_ptr = notes_section;
651-
while (real_sz < max_sz) {
652-
if (nhdr_ptr->n_namesz == 0)
653-
break;
658+
while (nhdr_ptr->n_namesz != 0) {
654659
sz = sizeof(Elf32_Nhdr) +
655660
((nhdr_ptr->n_namesz + 3) & ~3) +
656661
((nhdr_ptr->n_descsz + 3) & ~3);
662+
if ((real_sz + sz) > max_sz) {
663+
pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
664+
nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
665+
break;
666+
}
657667
real_sz += sz;
658668
nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
659669
}
660670
kfree(notes_section);
661671
phdr_ptr->p_memsz = real_sz;
672+
if (real_sz == 0) {
673+
pr_warn("Warning: Zero PT_NOTE entries found\n");
674+
return -EINVAL;
675+
}
662676
}
663677

664678
return 0;

0 commit comments

Comments
 (0)