[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen master] x86/pv: Inject #UD for missing SYSCALL callbacks



commit ca6fcf4321b31df0b50720fa817e727b16e34f76
Author:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
AuthorDate: Fri Jun 26 11:32:00 2020 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Tue Jan 26 10:18:33 2021 +0000

    x86/pv: Inject #UD for missing SYSCALL callbacks
    
    Despite appearing to be a deliberate design choice of early PV64, the
    resulting behaviour for unregistered SYSCALL callbacks creates an untenable
    testability problem for Xen.  Furthermore, the behaviour is undocumented,
    bizarre, and inconsistent with related behaviour in Xen, and very liable
    introduce a security vulnerability into a PV guest if the author hasn't
    studied Xen's assembly code in detail.
    
    There are two different bugs here.
    
    1) The current logic confuses the registered entrypoints, and may deliver a
       SYSCALL from 32bit userspace to the 64bit entry, when only a 64bit
       entrypoint is registered.
    
       This has been the case ever since 2007 (c/s cd75d47348b) but up until
       2018 (c/s dba899de14) the wrong selectors would be handed to the guest 
for
       a 32bit SYSCALL entry, making it appear as if it a 64bit entry all along.
    
       Xen would malfunction under these circumstances, if it were a PV guest.
       Linux would as well, but PVOps has always registered both entrypoints and
       discarded the Xen-provided selectors.  NetBSD really does malfunction as 
a
       consequence (benignly now, but a VM DoS before the 2018 Xen selector 
fix).
    
    2) In the case that neither SYSCALL callbacks are registered, the guest will
       be crashed when userspace executes a SYSCALL instruction, which is a
       userspace => kernel DoS.
    
       This has been the case ever since the introduction of 64bit PV support, 
but
       behaves unlike all other SYSCALL/SYSENTER callbacks in Xen, which yield
       #GP/#UD in userspace before the callback is registered, and are therefore
       safe by default.
    
    This change does constitute a change in the PV ABI, for corner cases of a PV
    guest kernel registering neither callback, or not registering the 32bit
    callback when running on AMD/Hygon hardware.
    
    It brings the behaviour in line with PV32 SYSCALL/SYSENTER, and PV64
    SYSENTER (safe by default, until explicitly enabled), as well as native
    hardware (always delivered to the single applicable callback).
    
    Most importantly however, and the primary reason for the change, is that it
    lets us sensibly test the fast system call entrypoints under all states a PV
    guest can construct, to prove correct behaviour.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Acked-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
 xen/arch/x86/x86_64/entry.S | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 7292ae8493..b5688e2c34 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -26,18 +26,30 @@
 /* %rbx: struct vcpu */
 ENTRY(switch_to_kernel)
         leaq  VCPU_trap_bounce(%rbx),%rdx
-        /* TB_eip = (32-bit syscall && syscall32_addr) ?
-         *          syscall32_addr : syscall_addr */
-        xor   %eax,%eax
+
+        /* TB_eip = 32-bit syscall ? syscall32_addr : syscall_addr */
+        mov   VCPU_syscall32_addr(%rbx), %rcx
+        mov   VCPU_syscall_addr(%rbx), %rax
         cmpw  $FLAT_USER_CS32,UREGS_cs(%rsp)
-        cmoveq VCPU_syscall32_addr(%rbx),%rax
-        testq %rax,%rax
-        cmovzq VCPU_syscall_addr(%rbx),%rax
-        movq  %rax,TRAPBOUNCE_eip(%rdx)
+        cmove %rcx, %rax
+
         /* TB_flags = VGCF_syscall_disables_events ? TBF_INTERRUPT : 0 */
         btl   $_VGCF_syscall_disables_events,VCPU_guest_context_flags(%rbx)
         setc  %cl
         leal  (,%rcx,TBF_INTERRUPT),%ecx
+
+        test  %rax, %rax
+UNLIKELY_START(z, syscall_no_callback) /* TB_eip == 0 => #UD */
+        mov   VCPU_trap_ctxt(%rbx), %rdi
+        movl  $X86_EXC_UD, UREGS_entry_vector(%rsp)
+        subl  $2, UREGS_rip(%rsp)
+        mov   X86_EXC_UD * TRAPINFO_sizeof + TRAPINFO_eip(%rdi), %rax
+        testb $4, X86_EXC_UD * TRAPINFO_sizeof + TRAPINFO_flags(%rdi)
+        setnz %cl
+        lea   TBF_EXCEPTION(, %rcx, TBF_INTERRUPT), %ecx
+UNLIKELY_END(syscall_no_callback)
+
+        movq  %rax,TRAPBOUNCE_eip(%rdx)
         movb  %cl,TRAPBOUNCE_flags(%rdx)
         call  create_bounce_frame
         andl  $~X86_EFLAGS_DF,UREGS_eflags(%rsp)
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.