• Dmitry Safonov's avatar
    x86/mm: Make in_compat_syscall() work during exec · ada26481
    Dmitry Safonov authored
    The x86 mmap() code selects the mmap base for an allocation depending on
    the bitness of the syscall. For 64bit sycalls it select mm->mmap_base and
    for 32bit mm->mmap_compat_base.
    
    On execve the registers of the task invoking exec() are copied to the child
    pt_regs. So child->pt_regs->orig_ax contains the execve syscall number of the
    parent.
    
    exec() calls mmap() which in turn uses in_compat_syscall() to check whether
    the mapping is for a 32bit or a 64bit task. The decision is made on the
    following criteria:
    
      ia32	  child->thread.status & TS_COMPAT
       x32	  child->pt_regs.orig_ax & __X32_SYSCALL_BIT
      ia64	  !ia32 && !x32 
    
    child->thread.status is corretly set up in set_personality_*(), but the
    syscall number in child->pt_regs.orig_ax is left unmodified.
    
    Therefore the parent/child combinations work or fail in the following way:
    
    Parent Child Child->thread_status  child->pt_regs.orig_ax  in_compat()  Works
    ia64    ia64   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 0     false       Y
    ia64    ia32   TS_COMPAT == 1	   __X32_SYSCALL_BIT == 0     true        Y
    ia64     x32   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 0     false       N
    ia32    ia64   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 0     false       Y
    ia32    ia32   TS_COMPAT == 1	   __X32_SYSCALL_BIT == 0     true        Y
    ia32     x32   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 0     false       N
     x32    ia64   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 1     true        N
     x32    ia32   TS_COMPAT == 1	   __X32_SYSCALL_BIT == 1     true        Y
     x32     x32   TS_COMPAT == 0	   __X32_SYSCALL_BIT == 1     true        Y
    
    Make set_personality_*() store the syscall number incl. __X32_SYSCALL_BIT
    which corresponds to the newly started ELF executable in the childs
    pt_regs, i.e. pretend that the exec was invoked from a task with the same
    executable format.
    
    So both thread.status and pt_regs.orig_ax correspond to the new ELF format
    and in_compat_syscall() returns the correct result.
    
    [ tglx: Rewrote changelog ]
    
    Fixes: commit 1b028f78 ("x86/mm: Introduce mmap_compat_base() for 32-bit mmap()")
    Reported-by: default avatarAdam Borowski <kilobyte@angband.pl>
    Suggested-by: default avatarH. Peter Anvin <hpa@zytor.com>
    Suggested-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarDmitry Safonov <dsafonov@virtuozzo.com>
    Cc: 0x7f454c46@gmail.com
    Cc: linux-mm@kvack.org
    Cc: Andrei Vagin <avagin@gmail.com>
    Cc: Andy Lutomirski <luto@kernel.org>
    Cc: Cyrill Gorcunov <gorcunov@openvz.org>
    Cc: Borislav Petkov <bp@suse.de>
    Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
    Link: http://lkml.kernel.org/r/20170331111137.28170-1-dsafonov@virtuozzo.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    ada26481
process_64.c 18 KB