[Devel] [PATCH RHEL7 COMMIT] ms/x86/coredump: Always use user_regs_struct for compat_elf_gregset_t

Konstantin Khorenko khorenko at virtuozzo.com
Fri Nov 25 06:30:37 PST 2016


The commit is pushed to "branch-rh7-3.10.0-327.36.1.vz7.20.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.36.1.vz7.20.3
------>
commit 8b91c39348766ffa72cd310463657978ff5c1dcf
Author: Dmitry Safonov <dsafonov at virtuozzo.com>
Date:   Fri Nov 25 18:30:37 2016 +0400

    ms/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 at virtuozzo.com>
    
    Cc: Andy Lutomirski <luto at kernel.org>
    Cc: Andy Lutomirski <luto at kernel.org>
    Cc: Borislav Petkov <bp at alien8.de>
    Cc: Brian Gerst <brgerst at gmail.com>
    Cc: Denys Vlasenko <dvlasenk at redhat.com>
    Cc: H. Peter Anvin <hpa at zytor.com>
    Cc: Linus Torvalds <torvalds at linux-foundation.org>
    Cc: Peter Zijlstra <peterz at infradead.org>
    Cc: Thomas Gleixner <tglx at linutronix.de>
    Cc: Josh Poimboeuf <jpoimboe at redhat.com>
    Cc: Linus Torvalds <torvalds at linux-foundation.org>
    Cc: Oleg Nesterov <oleg at redhat.com>
    Cc: Peter Zijlstra <peterz at infradead.org>
    Cc: Thomas Gleixner <tglx at linutronix.de>
    Cc: linux-mm at kvack.org
    Fixes: 90954e7b9407 ("x86/coredump: Use pr_reg size, rather that TIF_IA32 flag")
    Signed-off-by: Ingo Molnar <mingo at kernel.org>
    
    [applied from x86 git-tip for v4.9]
    Gitweb: http://git.kernel.org/tip/7b2dd3682896bcf1abbbbe870885728db2832a3c
    Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 arch/x86/include/asm/compat.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index 6a07267..6ea296d 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -261,7 +261,6 @@ struct compat_shmid64_ds {
 /*
  * The type of struct elf_prstatus.pr_reg in compatible core dumps.
  */
-#ifdef CONFIG_X86_X32_ABI
 typedef struct user_regs_struct compat_elf_gregset_t;
 
 /* Full regset -- prstatus on x32, otherwise on ia32 */
@@ -270,10 +269,9 @@ typedef struct user_regs_struct compat_elf_gregset_t;
   do { *(int *) (((void *) &((S)->pr_reg)) + R) = (V); } \
   while (0)
 
+#ifdef CONFIG_X86_X32_ABI
 #define COMPAT_USE_64BIT_TIME \
 	(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
-#else
-typedef struct user_regs_struct32 compat_elf_gregset_t;
 #endif
 
 /*


More information about the Devel mailing list