diff options
author | Dmitry Safonov <dsafonov@virtuozzo.com> | 2016-11-23 13:13:30 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-11-24 00:01:05 -0500 |
commit | 7b2dd3682896bcf1abbbbe870885728db2832a3c (patch) | |
tree | bc5b3d25f16ddc3b1e0c524941b70b9dca4939bb | |
parent | 10b9dd56860e93f11cd352e8c75a33357b80b70b (diff) |
x86/coredump: Always use user_regs_struct for compat_elf_gregset_t
Commit:
90954e7b9407 ("x86/coredump: Use pr_reg size, rather that TIF_IA32 flag")
changed the coredumping code to construct the elf coredump file according
to register set size - and that's good: if binary crashes with 32-bit code
selector, generate 32-bit ELF core, otherwise - 64-bit core.
That was made for restoring 32-bit applications on x86_64: we want
32-bit application after restore to generate 32-bit ELF dump on crash.
All was quite good and recently I started reworking 32-bit applications
dumping part of CRIU: now it has two parasites (32 and 64) for seizing
compat/native tasks, after rework it'll have one parasite, working in
64-bit mode, to which 32-bit prologue long-jumps during infection.
And while it has worked for my work machine, in VM with
!CONFIG_X86_X32_ABI during reworking I faced that segfault in 32-bit
binary, that has long-jumped to 64-bit mode results in dereference
of garbage:
32-victim[19266]: segfault at f775ef65 ip 00000000f775ef65 sp 00000000f776aa50 error 14
BUG: unable to handle kernel paging request at ffffffffffffffff
IP: [<ffffffff81332ce0>] strlen+0x0/0x20
[...]
Call Trace:
[] elf_core_dump+0x11a9/0x1480
[] do_coredump+0xa6b/0xe60
[] get_signal+0x1a8/0x5c0
[] do_signal+0x23/0x660
[] exit_to_usermode_loop+0x34/0x65
[] prepare_exit_to_usermode+0x2f/0x40
[] retint_user+0x8/0x10
That's because we have 64-bit registers set (with according total size)
and we're writing it to elf_thread_core_info which has smaller size
on !CONFIG_X86_X32_ABI. That lead to overwriting ELF notes part.
Tested on 32-, 64-bit ELF crashes and on 32-bit binaries that have
jumped with 64-bit code selector - all is readable with gdb.
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-mm@kvack.org
Fixes: 90954e7b9407 ("x86/coredump: Use pr_reg size, rather that TIF_IA32 flag")
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/compat.h | 4 |
1 files changed, 1 insertions, 3 deletions
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 03d269bed941..24118c0b4640 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h | |||
@@ -272,7 +272,6 @@ struct compat_shmid64_ds { | |||
272 | /* | 272 | /* |
273 | * The type of struct elf_prstatus.pr_reg in compatible core dumps. | 273 | * The type of struct elf_prstatus.pr_reg in compatible core dumps. |
274 | */ | 274 | */ |
275 | #ifdef CONFIG_X86_X32_ABI | ||
276 | typedef struct user_regs_struct compat_elf_gregset_t; | 275 | typedef struct user_regs_struct compat_elf_gregset_t; |
277 | 276 | ||
278 | /* Full regset -- prstatus on x32, otherwise on ia32 */ | 277 | /* Full regset -- prstatus on x32, otherwise on ia32 */ |
@@ -281,10 +280,9 @@ typedef struct user_regs_struct compat_elf_gregset_t; | |||
281 | do { *(int *) (((void *) &((S)->pr_reg)) + R) = (V); } \ | 280 | do { *(int *) (((void *) &((S)->pr_reg)) + R) = (V); } \ |
282 | while (0) | 281 | while (0) |
283 | 282 | ||
283 | #ifdef CONFIG_X86_X32_ABI | ||
284 | #define COMPAT_USE_64BIT_TIME \ | 284 | #define COMPAT_USE_64BIT_TIME \ |
285 | (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)) | 285 | (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)) |
286 | #else | ||
287 | typedef struct user_regs_struct32 compat_elf_gregset_t; | ||
288 | #endif | 286 | #endif |
289 | 287 | ||
290 | /* | 288 | /* |