Hi, I used crash to analyze a vmcore and found that when crash calculates the bitmap and pfn, an integer
overflow occurs, causing the crash parsing to fail. [root@localhost userspace]# crash vmlinux vmcore …… reason: variable overflow causes a logic error in crash. crash: page excluded: kernel virtual address: ffff0000089c9100 type: "kernel_config_data" WARNING: cannot read kernel_config_data crash: page excluded: kernel virtual address: ffff00000911b938 type: "possible" WARNING: cannot read cpu_possible_map crash: page excluded: kernel virtual address: ffff00000911b8b8 type: "present" WARNING: cannot read cpu_present_map crash: page excluded: kernel virtual address: ffff00000911b838 type: "online" WARNING: cannot read cpu_online_map crash: page excluded: kernel virtual address: ffff00000911b9b8 type: "active" WARNING: cannot read cpu_active_map crash: page excluded: kernel virtual address: ffff0000093ec9d0 type: "shadow_timekeeper xtime_sec" crash: page excluded: kernel virtual address: ffff000009124d2c type: "init_uts_ns" crash: vmlinux and vmcore do not match! And the /proc/iomem info: 2e69267000-2fffffffff : System RAM ...... 602770ecf000-6027ffffffff : System RAM
Here is the process of my analysis:
1. calculate bitmap_len overflow in function read_dump_header() int block_size=(int)sysconf(_SC_PAGESIZE); off_t bitmap_len; unsigned int bitmap_blocks; ... bitmap_len = block_size * header->bitmap_blocks; here block_size = 4096, header->bitmap_blocks = 0x180a00, so bitmap_len = 0x180a00000 but block_size is integer type, bitmap_blocks is unsigned int type, so block_size * header->bitmap_blocks >
MAX(unsigned int) bitmap_len overflow.
2. calculate data_offset overflow in function read_dump_header() dd->data_offset = (1 + header->sub_hdr_size + header->bitmap_blocks) * header->block_size;
info in makedumpfile: info->offset_bitmap1=0x15000 info->len_bitmap=0x182000000 bit2_offset=0xc1015000 in read_dump_header(): info->len_bitmap = header->bitmap_blocks * header->block_size = 0x182000000 is greater than the range represented
by integers. The members of the following _expression_ are all int type, but the calculation result exceeds MAX(int), dd->data_offset = (1 + header->sub_hdr_size + header->bitmap_blocks) * header->block_size = 0x82015000, The correct value is 0x182015000.
3. byte parameter overflow in function get_bit() static inline int get_bit(char *map, int byte, int bit) { return map[byte] & (1<<bit); } static inline int page_is_ram(unsigned long nr) { return get_bit(dd->bitmap, nr >> 3, nr & 7); } if nr=0x6027fff4f, 0x6027fff4f >> 3 => 0xC04FFFE9 > MAX(int), so byte parameter overflow when call get_bit.
The following is my patch, please review. Thanks. Signed-off-by: Jialong Chen <chenjialong@xxxxxxxxxx> --- diskdump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/diskdump.c b/diskdump.c index e88243e..328c932 100644 --- a/diskdump.c +++ b/diskdump.c @@ -233,7 +233,7 @@ clean_diskdump_data(void) } static inline int
-get_bit(char *map, int byte, int bit) +get_bit(char *map, unsigned long byte, int bit) { return map[byte] & (1<<bit); } @@ -694,7 +694,7 @@ restart: dd->max_mapnr = header->max_mapnr; /* read memory bitmap */ - bitmap_len = block_size * header->bitmap_blocks; + bitmap_len = (off_t)block_size * header->bitmap_blocks; dd->bitmap_len = bitmap_len; offset = (off_t)block_size * (1 + header->sub_hdr_size); @@ -744,7 +744,7 @@ restart: memcpy(dd->dumpable_bitmap, dd->bitmap, bitmap_len); dd->data_offset - = (1 + header->sub_hdr_size + header->bitmap_blocks) + = (1UL + header->sub_hdr_size + header->bitmap_blocks) * header->block_size; dd->header = header; --
1.7.12.4 |
Attachment:
0001-bitmap-calculation-overflow-in-large-physical-addres.patch
Description: 0001-bitmap-calculation-overflow-in-large-physical-addres.patch
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility