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@huawei.com>
---
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