From 357af1f7b26da928d916e7b3c571e51dec58d1c9 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke Date: Thu, 25 Oct 2012 11:19:58 +0900 Subject: [PATCH] netdump: fix NULL pointer dereference when no NT_PRSTATUS exists We faced a vmcore with no NT_PRSTATUS. netdump code now assumes that there is at least one NT_PRSTATUS note. (The assumption is correct since NT_PRSTATUS is per-cpu note information and normal machine has always at least one logical processor.) So, crash resulted in NULL pointer dereference when reading this vmcore. The vmcore was generated by kdump on Xen HVM. Unfortunately, kexec on the system had yet to support Xen HVM, it wrongly entered logic for Xen DOM0. On DOM0, positions of NT_PRSTATUS is available from Crash note entries in /proc/iomem. But since it was actually Xen HVM, there is no Crash note entry. So, the resulted vmcore had no NT_PRSTATUS note. The cause of this was using kexec that didn't support Xen HVM. But there might be cases in the future that vmcore with no NT_PRSTATUS is generated from any reason. Then, it's useful to be analyze the vmcore with even no NT_PRSTATUS. Signed-off-by: HATAYAMA Daisuke --- netdump.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 38 insertions(+), 0 deletions(-) diff --git a/netdump.c b/netdump.c index c16eaab..20bf2f7 100644 --- a/netdump.c +++ b/netdump.c @@ -2348,6 +2348,9 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) else note = (Elf64_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); len = roundup(len + note->n_descsz, 4); @@ -2384,6 +2387,10 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) (bt->flags & BT_DUMPFILE_SEARCH) && DISKDUMP_DUMPFILE() && (note = (Elf64_Nhdr *) diskdump_get_prstatus_percpu(bt->tc->processor))) { + + if (!note) + goto no_nt_prstatus_exists; + user_regs = get_regs_from_note((char *)note, &rip, &rsp); if (CRASHDEBUG(1)) @@ -2399,6 +2406,7 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) bt->machdep = (void *)user_regs; } +no_nt_prstatus_exists: machdep->get_stack_frame(bt, ripp, rspp); } @@ -2668,12 +2676,16 @@ get_netdump_regs_ppc(struct bt_info *bt, ulong *eip, ulong *esp) } else note = (Elf32_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf32_Nhdr); len = roundup(len + note->n_namesz, 4); bt->machdep = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); } +no_nt_prstatus_exists: machdep->get_stack_frame(bt, eip, esp); } @@ -2702,12 +2714,16 @@ get_netdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp) } else note = (Elf64_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); bt->machdep = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); } +no_nt_prstatus_exists: machdep->get_stack_frame(bt, eip, esp); } @@ -3085,6 +3101,10 @@ get_x86_regs_from_elf_notes(struct task_context *tc) note = (void *)nd->nt_prstatus_percpu[tc->processor]; else note = (void *)nd->nt_prstatus; + + if (!note) + goto no_nt_prstatus_exists; + if (nd->elf32) { note_32 = (Elf32_Nhdr *)note; len = sizeof(Elf32_Nhdr); @@ -3100,6 +3120,7 @@ get_x86_regs_from_elf_notes(struct task_context *tc) /* NEED TO BE FIXED: Hack to get the proper alignment */ pt_regs +=4; +no_nt_prstatus_exists: return pt_regs; } @@ -3118,11 +3139,15 @@ get_x86_64_regs_from_elf_notes(struct task_context *tc) else note = (Elf64_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); pt_regs = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); +no_nt_prstatus_exists: return pt_regs; } @@ -3146,11 +3171,15 @@ get_ppc_regs_from_elf_notes(struct task_context *tc) } else note = (Elf32_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf32_Nhdr); len = roundup(len + note->n_namesz, 4); pt_regs = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); +no_nt_prstatus_exists: return pt_regs; } @@ -3174,11 +3203,15 @@ get_ppc64_regs_from_elf_notes(struct task_context *tc) } else note = (Elf64_Nhdr *)nd->nt_prstatus; + if (!note) + goto no_nt_prstatus_exists; + len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); pt_regs = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); +no_nt_prstatus_exists: return pt_regs; } @@ -3225,6 +3258,10 @@ get_arm_regs_from_elf_notes(struct task_context *tc) note = (void *)nd->nt_prstatus_percpu[tc->processor]; else note = (void *)nd->nt_prstatus; + + if (!note) + goto no_nt_prstatus_exists; + if (nd->elf32) { note_32 = (Elf32_Nhdr *)note; len = sizeof(Elf32_Nhdr); @@ -3238,6 +3275,7 @@ get_arm_regs_from_elf_notes(struct task_context *tc) pt_regs = (void *)((char *)note + len + MEMBER_OFFSET("elf_prstatus", "pr_reg")); +no_nt_prstatus_exists: return pt_regs; } -- 1.7.7.6