RetSpill: Igniting User-Controlled Data to Burn Away Linux Kernel Protections


int do_sys_poll (...) 2 { 3 long



tải về 0.65 Mb.
Chế độ xem pdf
trang3/10
Chuyển đổi dữ liệu15.12.2023
Kích0.65 Mb.
#56016
1   2   3   4   5   6   7   8   9   10
retspill

int
do_sys_poll
(...)
2
{
3
long
stack_pps[POLL_STACK_ALLOC
/
sizeof
(
long
)];
4
struct
poll_list
*
walk
=
(
struct
poll_list
*
)stack_pps;
5
6
// copy user space data onto kernel stack
7
copy_from_user(walk
->
entries, ufds,
sizeof
(walk
->
entries);
8
9
// invoke poll handler for each fd
10
pfd
=
walk
->
entries;
11
for
(; ... ; pfd
++
) {
12
file
=
fdget(pfd).file;
13
file
->
f_op
->
poll(...);
14
}
15
...
16
}
Listing 1: The simplified code snippet of poll system call
handler in the Linux kernel.
gadget to pivot into the controlled region and launch code reuse
attacks. During the lifetime of the poll system call, the on-stack
data is valid (i.e., its presence on the kernel stack is not a security
violation), but it is used for malicious purposes.
Preserved Registers.
Each user space thread has its own kernel
stack. When the user space thread invokes a system call, the kernel
will switch to using the associated kernel stack by setting the rsp
register. Immediately following the stack pointer change, the kernel
pushes the user space context onto the kernel stack to preserve
the context as shown in Figure 1. Here, the “user space context” is
a data structure called pt_regs [65] that includes all of the user
space registers. These values can be carefully set by malicious users
before invoking the system call.
In other words, a fully user-controllable region is at the bottom
of the kernel stack. When the attacker triggers a CFHP, they can
use the controlled pt_regs region as a ROP payload.
Calling Convention.
In the Linux kernel’s calling conven-
tion [62], callee and caller functions both need to preserve sets
of registers, termed “callee-saved” and “caller-saved” registers. The
way compilers implement the calling convention is by emitting
code to push the registers that will be potentially clobbered in the
function to the kernel stack at the function prologue and pop them
at the epilogue. This mechanism gives attackers two ways to place
controlled data onto the stack.
First, registers can be pushed onto the kernel stack when the
kernel invokes the actual system call handler function to serve the
system call. System call handlers are invoked right after userspace
registers are pushed onto the kernel stack as pt_regs. At the time of
invoking system call handlers, the registers still contain userspace
data. Since system call handlers are calling convention compliant,
they will save registers that will be clobbered within the handler
by pushing them onto the stack as well.
Second, the system call handlers might call other helper func-
tions, which will also be calling convention compliant, and registers
still containing user space data (or reloaded with user space data in
the course of system call servicing) might be saved as a result.
Uninitialized Memory.
Since there is only one kernel stack for
each thread, data used in previous system calls within the same
thread can be left on the kernel stack if not overwritten by the
triggering system call. Due to the fact that the kernel’s control flow
is usually hijacked in the middle of a function, variables used after
the hijacking point will not be initialized by design. In other words,
1

tải về 0.65 Mb.

Chia sẻ với bạn bè của bạn:
1   2   3   4   5   6   7   8   9   10




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương