• A
    selftests/x86: Add a selftest for SYSRET to noncanonical addresses · 66060214
    Andy Lutomirski 提交于
    SYSRET to a noncanonical address will blow up on Intel CPUs.  Linux
    needs to prevent this from happening in two major cases, and the
    criteria will become more complicated when support for larger virtual
    address spaces is added.
    
    A fast-path SYSCALL will fall through to the following instruction
    using SYSRET without any particular checking.  To prevent fall-through
    to a noncanonical address, Linux prevents the highest canonical page
    from being mapped.  This test case checks a variety of possible maximum
    addresses to make sure that either we can't map code there or that
    SYSCALL fall-through works.
    
    A slow-path system call can return anywhere.  Linux needs to make sure
    that, if the return address is non-canonical, it won't use SYSRET.
    This test cases causes sigreturn() to return to a variety of addresses
    (with RCX == RIP) and makes sure that nothing explodes.
    
    Some of this code comes from Kirill Shutemov.
    
    Kirill reported the following output with 5-level paging enabled:
    
      [RUN]   sigreturn to 0x800000000000
      [OK]    Got SIGSEGV at RIP=0x800000000000
      [RUN]   sigreturn to 0x1000000000000
      [OK]    Got SIGSEGV at RIP=0x1000000000000
      [RUN]   sigreturn to 0x2000000000000
      [OK]    Got SIGSEGV at RIP=0x2000000000000
      [RUN]   sigreturn to 0x4000000000000
      [OK]    Got SIGSEGV at RIP=0x4000000000000
      [RUN]   sigreturn to 0x8000000000000
      [OK]    Got SIGSEGV at RIP=0x8000000000000
      [RUN]   sigreturn to 0x10000000000000
      [OK]    Got SIGSEGV at RIP=0x10000000000000
      [RUN]   sigreturn to 0x20000000000000
      [OK]    Got SIGSEGV at RIP=0x20000000000000
      [RUN]   sigreturn to 0x40000000000000
      [OK]    Got SIGSEGV at RIP=0x40000000000000
      [RUN]   sigreturn to 0x80000000000000
      [OK]    Got SIGSEGV at RIP=0x80000000000000
      [RUN]   sigreturn to 0x100000000000000
      [OK]    Got SIGSEGV at RIP=0x100000000000000
      [RUN]   sigreturn to 0x200000000000000
      [OK]    Got SIGSEGV at RIP=0x200000000000000
      [RUN]   sigreturn to 0x400000000000000
      [OK]    Got SIGSEGV at RIP=0x400000000000000
      [RUN]   sigreturn to 0x800000000000000
      [OK]    Got SIGSEGV at RIP=0x800000000000000
      [RUN]   sigreturn to 0x1000000000000000
      [OK]    Got SIGSEGV at RIP=0x1000000000000000
      [RUN]   sigreturn to 0x2000000000000000
      [OK]    Got SIGSEGV at RIP=0x2000000000000000
      [RUN]   sigreturn to 0x4000000000000000
      [OK]    Got SIGSEGV at RIP=0x4000000000000000
      [RUN]   sigreturn to 0x8000000000000000
      [OK]    Got SIGSEGV at RIP=0x8000000000000000
      [RUN]   Trying a SYSCALL that falls through to 0x7fffffffe000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x7ffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x800000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0xfffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x1000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x1fffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x2000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x3fffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x4000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x7fffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x8000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0xffffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x10000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x1ffffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x20000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x3ffffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x40000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x7ffffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x80000000000000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0xfffffffffff000
      [OK]    We survived
      [RUN]   Trying a SYSCALL that falls through to 0x100000000000000
      [OK]    mremap to 0xfffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x1fffffffffff000
      [OK]    mremap to 0x1ffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x200000000000000
      [OK]    mremap to 0x1fffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x3fffffffffff000
      [OK]    mremap to 0x3ffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x400000000000000
      [OK]    mremap to 0x3fffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x7fffffffffff000
      [OK]    mremap to 0x7ffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x800000000000000
      [OK]    mremap to 0x7fffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0xffffffffffff000
      [OK]    mremap to 0xfffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x1000000000000000
      [OK]    mremap to 0xffffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x1ffffffffffff000
      [OK]    mremap to 0x1fffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x2000000000000000
      [OK]    mremap to 0x1ffffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x3ffffffffffff000
      [OK]    mremap to 0x3fffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x4000000000000000
      [OK]    mremap to 0x3ffffffffffff000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x7ffffffffffff000
      [OK]    mremap to 0x7fffffffffffe000 failed
      [RUN]   Trying a SYSCALL that falls through to 0x8000000000000000
      [OK]    mremap to 0x7ffffffffffff000 failed
    Signed-off-by: NAndy Lutomirski <luto@kernel.org>
    Acked-by: NKirill A. Shutemov <kirill.shutemov@linux.intel.com>
    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: Josh Poimboeuf <jpoimboe@redhat.com>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Shuah Khan <shuahkh@osg.samsung.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Link: http://lkml.kernel.org/r/e70bd9a3f90657ba47b755100a20475d038fa26b.1482808435.git.luto@kernel.orgSigned-off-by: NIngo Molnar <mingo@kernel.org>
    66060214
sysret_rip.c 4.8 KB