Simplify sysretq code.

This commit is contained in:
4lDO2
2021-02-15 19:04:43 +01:00
parent 5b2df9f504
commit 8eb58891aa

View File

@@ -58,19 +58,6 @@ pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack)
});
}
macro_rules! fast_sysretq {
() => { "
pop rcx // Pop userspace return pointer
sub rsp, 8 // Pop fake userspace CS
pop r11 // Pop rflags
pop QWORD PTR gs:[0x70] // Pop userspace stack pointer
mov rsp, gs:[0x70] // Restore userspace stack pointer
swapgs // Restore gs from TSS to user data
ud2
sysretq // Return into userspace; RCX=>RIP,R11=>RFLAGS
" }
}
function!(syscall_instruction => {
// Yes, this is magic. No, you don't need to understand
"
@@ -106,51 +93,36 @@ function!(syscall_instruction => {
pop_scratch!(),
// Return
//
// We must test whether RCX is canonical. This is not strictly necessary, but could be
// fatal if some kernel bug would allow RCX to be modified by user code.
//
// See https://xenproject.org/2012/06/13/the-intel-sysret-privilege-escalation/.
//
// This is not just theoretical; ptrace allows userspace to change rcx of target processes.
"
// Test whether RCX is canonical. This is not strictly necessary, but could be fatal if
// some kernel bug would allow RCX to be modified by user code.
pop rcx // Pop userspace return pointer
// Peek at the preserved RCX, to double-check that it is canonical.
// Set ZF iff bit 47 (i.e. the bit that must be sign extended) is set.
// Set ZF iff forbidden bit 47 (i.e. the bit that must be sign extended) is set.
bt rcx, 47
// TODO: Any hacky one-instruction canonicalness check?
// If ZF was set, i.e. the address was invalid higher-half, so jump to the slower iretq and
// handle the error without being able to execute attacker-controlled code!
jmp 1f
bt QWORD PTR [rsp], 47
// Otherwise, continue with the fast sysretq.
// Jump to the canonicalness check.
jnz 2f
sub rsp, 8 // Pop fake userspace CS
pop r11 // Pop rflags
pop QWORD PTR gs:[0x70] // Pop userspace stack pointer
mov rsp, gs:[0x70] // Restore userspace stack pointer
swapgs // Restore gs from TSS to user data
sysretq // Return into userspace; RCX=>RIP,R11=>RFLAGS
// Otherwise, continue with the fast return.
1:
// Fast sysretq
",
1:
fast_sysretq!(),
"
// Jumps to aligned addresses are faster, and it is not always the case the userspace
// doesn't call from higher half (though unlikely).
.align 8, 0x90
2:
// Load userspace return RIP.
mov rcx, [rsp]
// Shift it to the right by 47, only getting the bits which must all be zero or one.
shr rcx, 47
// Since we have already checked that RCX[47] == 1, RCX[63:47] must all be one.
cmp rcx, 0x1FFFF
// If the address is canonical, go to the slower iretq.
jne 3f
",
fast_sysretq!(),
"
3:
// Slow iretq
push rcx
xor rcx, rcx
xor r11, r11
swapgs