[makedumpfile PATCH v3] Prevent data loss in last page of ELF core dumpfile

Atsushi Kumagai ats-kumagai at wm.jp.nec.com
Thu Jul 6 19:36:06 PDT 2017


Hello Eric,

Thanks! I'll merge this version into v1.6.2.

Regards,
Atsushi Kumagai

>When generating an ELF core dump file, if a segment size
>is not an exact multiple of PAGE_SIZE, then the corresponding
>generated segment is erroneously truncated to a PAGE_SIZE multiple.
>Thus a small loss of data up to PAGE_SIZE-1 bytes can occur.
>
>The problem root is in the creation of the first bitmap, which
>is the list of pages to dump as calculated from the vmcore
>segments' information. (A second bitmap is created which is
>a copy of the first bitmap with those bits corresponding to the
>exclude/filter pages zero'd, and is the actual list of dumpable
>pages).
>
>During creation of the first bitmap, each segment is processed
>to determine the first and last page frame numbers corresponding
>to the segment. The page dump loops are generally written as:
>
>  for (pfn = pfn_start; pfn < pfn_end; ++pfn)
>
>meaning that the pfn_end needs to be one beyond the actual last
>page frame number.
>
>The last page frame number is calculated via the paddr_to_pfn()
>macro on the segment end physical address of p_addr + p_memsz.
>The paddr_to_pfn() macro essentially performs a right shift of
>the address to extract the pfn. Since p_memsz is typically a
>multiple of PAGE_SIZE, the computed pfn_end is one beyond the
>actual. For example, a segment which describes the first page of
>memory would be p_paddr 0 + p_memsz 0x1000 = 0x1000, and when
>right shifted yields pfn_end of 1, matching the loop semantics
>above and resulting in one iteration of the loop.
>
>However, when the end physical address is not a multiple of
>PAGE_SIZE, the paddr_to_pfn() macro truncates the address and
>the need for one additional page for the remaining data is
>unaccounted. For example, a segment which describes the 4097
>bytes (PAGE_SIZE + 1), results in p_addr 0 + p_memsz 0x1001 =
>0x1001, and when right shifted yields pfn_end of 1. An additional
>page is needed to account for the additional data, so pfn_end
>needs to be 2 in this case.
>
>This patch detects this condition and accounts for the additional
>needed page.
>
>This problem was observed by the test case described below.
>
>I have an existing ELF vmcore dumpfile and run it through
>makedumpfile again, as such:
>
>% makedumpfile -E -x vmlinux vmcore newvmcore
>% readelf -a vmcore > vmcore.txt
>% readelf -a newvmcore > newvmcore.txt
>
>From crash, here is a description of the original vmcore:
>
>      KERNEL: vmlinux
>    DUMPFILE: vmcore
>        CPUS: 4
>        DATE: Thu Jan  7 07:49:10 2016
>      UPTIME: 00:00:22
>LOAD AVERAGE: 0.00, 0.00, 0.00
>       TASKS: 77
>    NODENAME: mini-amd64
>     RELEASE: 4.2.0-ns.gen.amd64.1
>     VERSION: #1 SMP Wed Oct 28 16:32:12 CET 2015
>     MACHINE: x86_64  (2194 Mhz)
>      MEMORY: 4 GB
>       PANIC: "sysrq: SysRq : Trigger a crash"
>         PID: 96
>     COMMAND: "bash"
>        TASK: ffff88017a4c9e00  [THREAD_INFO: ffff88017a198000]
>         CPU: 3
>       STATE: TASK_RUNNING (SYSRQ)
>
>In essence, no re-filtering has occured and I expect to see a very similar
>ELF dump file to the original.  And for the most part, the files are similar,
>but I do observe some differences.
>
>The contents of vmcore.txt are:
>
>=== vmcore.txt ===
>ELF Header:
>  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
>  Class:                             ELF64
>  Data:                              2's complement, little endian
>  Version:                           1 (current)
>  OS/ABI:                            UNIX - System V
>  ABI Version:                       0
>  Type:                              CORE (Core file)
>  Machine:                           Advanced Micro Devices X86-64
>  Version:                           0x1
>  Entry point address:               0x0
>  Start of program headers:          64 (bytes into file)
>  Start of section headers:          0 (bytes into file)
>  Flags:                             0x0
>  Size of this header:               64 (bytes)
>  Size of program headers:           56 (bytes)
>  Number of program headers:         6
>  Size of section headers:           0 (bytes)
>  Number of section headers:         0
>  Section header string table index: 0
>
>There are no sections in this file.
>
>There are no sections to group in this file.
>
>Program Headers:
>  Type           Offset             VirtAddr           PhysAddr
>                 FileSiz            MemSiz              Flags  Align
>  NOTE           0x0000000000001000 0x0000000000000000 0x0000000000000000
>                 0x0000000000000c6c 0x0000000000000c6c         0
>  LOAD           0x0000000000002000 0xffffffff81000000 0x0000000001000000
>                 0x0000000000829000 0x0000000000829000  RWE    0
>  LOAD           0x000000000082b000 0xffff880000001000 0x0000000000001000
>                 0x000000000009ec00 0x000000000009ec00  RWE    0
>  LOAD           0x00000000008ca000 0xffff880000100000 0x0000000000100000
>                 0x0000000003f00000 0x0000000003f00000  RWE    0
>  LOAD           0x00000000047ca000 0xffff880014000000 0x0000000014000000
>                 0x000000006bfdf000 0x000000006bfdf000  RWE    0
>  LOAD           0x00000000707a9000 0xffff880100000000 0x0000000100000000
>                 0x0000000080000000 0x0000000080000000  RWE    0
>
>There is no dynamic section in this file.
>
>There are no relocations in this file.
>
>The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
>
>Dynamic symbol information is not available for displaying symbols.
>
>No version information found in this file.
>
>Displaying notes found at file offset 0x00001000 with length 0x00000c6c:
>  Owner                 Data size	Description
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  VMCOREINFO           0x000006c1	Unknown note type: (0x00000000)
>=== vmcore.txt ===
>
>And the contents of newvmcore.txt:
>
>=== newvmcore.txt ===
>ELF Header:
>  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
>  Class:                             ELF64
>  Data:                              2's complement, little endian
>  Version:                           1 (current)
>  OS/ABI:                            UNIX - System V
>  ABI Version:                       0
>  Type:                              CORE (Core file)
>  Machine:                           Advanced Micro Devices X86-64
>  Version:                           0x1
>  Entry point address:               0x0
>  Start of program headers:          64 (bytes into file)
>  Start of section headers:          0 (bytes into file)
>  Flags:                             0x0
>  Size of this header:               64 (bytes)
>  Size of program headers:           56 (bytes)
>  Number of program headers:         6
>  Size of section headers:           0 (bytes)
>  Number of section headers:         0
>  Section header string table index: 0
>
>There are no sections in this file.
>
>There are no sections to group in this file.
>
>Program Headers:
>  Type           Offset             VirtAddr           PhysAddr
>                 FileSiz            MemSiz              Flags  Align
>  NOTE           0x0000000000000190 0x0000000000000000 0x0000000000000000
>                 0x0000000000000c6c 0x0000000000000c6c         0
>  LOAD           0x0000000000000dfc 0xffffffff81000000 0x0000000001000000
>                 0x0000000000829000 0x0000000000829000  RWE    0
>  LOAD           0x0000000000829dfc 0xffff880000001000 0x0000000000001000
>                 0x000000000009e000 0x000000000009ec00  RWE    0
>  LOAD           0x00000000008c7dfc 0xffff880000100000 0x0000000000100000
>                 0x0000000003f00000 0x0000000003f00000  RWE    0
>  LOAD           0x00000000047c7dfc 0xffff880014000000 0x0000000014000000
>                 0x000000006bfdf000 0x000000006bfdf000  RWE    0
>  LOAD           0x00000000707a6dfc 0xffff880100000000 0x0000000100000000
>                 0x0000000080000000 0x0000000080000000  RWE    0
>
>There is no dynamic section in this file.
>
>There are no relocations in this file.
>
>The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
>
>Dynamic symbol information is not available for displaying symbols.
>
>No version information found in this file.
>
>Displaying notes found at file offset 0x00000190 with length 0x00000c6c:
>  Owner                 Data size	Description
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  CORE                 0x00000150	NT_PRSTATUS (prstatus structure)
>  VMCOREINFO           0x000006c1	Unknown note type: (0x00000000)
>=== newvmcore.txt ===
>
>Ignoring the file offset differences, one can see that something
>changed on the second LOAD segment. The original vmcore has:
>
>  LOAD           0x000000000082b000 0xffff880000001000 0x0000000000001000
>                 0x000000000009ec00 0x000000000009ec00  RWE    0
>
>whereas the newvmcore has:
>
>  LOAD           0x0000000000829dfc 0xffff880000001000 0x0000000000001000
>                 0x000000000009e000 0x000000000009ec00  RWE    0
>                              ^^^^^
>
>Specifically, the file size for this segment in newvmcore is now 0x9e000
>rather than the 0x9ec00 of the original, a loss of data. (Since p_memsz
>is larger than p_filesz, those 0xc00 bytes become zeros in the handling
>of those addresses).
>
>With the patch applied, the file size is again correct.
>
>Signed-off-by: Eric DeVolder <eric.devolder at oracle.com>
>---
>v3: posted 06jul2017 to kexec-tools list
> - fix style/spacing issues noted by Daniel Kiper
>
>v2: posted 05jul2017 to kexec-tools list
> - feedback from Atsushi Kumagai pointed to real root of problem,
>   and patch changed accordingly
>
>v1: posted 03jul2017 to kexec-tools list
>---
> makedumpfile.c | 3 +++
> 1 file changed, 3 insertions(+)
>
>diff --git a/makedumpfile.c b/makedumpfile.c
>index e69b6df..fac5c2e 100644
>--- a/makedumpfile.c
>+++ b/makedumpfile.c
>@@ -5410,6 +5410,9 @@ create_1st_bitmap_file(void)
> 		if (pfn_start > info->max_mapnr)
> 			continue;
> 		pfn_end = MIN(pfn_end, info->max_mapnr);
>+		/* Account for last page if it has less than page_size data in it */
>+		if (phys_end & (info->page_size-1))
>+			++pfn_end;
>
> 		for (pfn = pfn_start; pfn < pfn_end; pfn++) {
> 			set_bit_on_1st_bitmap(pfn, NULL);
>--
>2.7.4
>





More information about the kexec mailing list