forked from opntr/pax-docs-mirror
-
Notifications
You must be signed in to change notification settings - Fork 1
/
emutramp.txt
75 lines (66 loc) · 4.6 KB
/
emutramp.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
1. Design
The goal of EMUTRAMP is to emulate certain instruction sequences that are
known to be generated at runtime in otherwise non-executable memory regions
and hence would cause task termination when the non-executable feature is
enforced (by PAGEEXEC or SEGMEXEC).
While there are many sources of runtime generated code, PaX emulates only
two of them: the kernel generated signal return stubs and the gcc nested
function trampolines. We chose to emulate them and only them because they
are the most common and still the shortest and best defined sequences. The
other reason is that runtime code generation is by its nature incompatible
with PaX's PAGEEXEC/SEGMEXEC and MPROTECT features, therefore the real
solution is not in emulation but by designing a kernel API for runtime
code generation and modifying userland to make use of it.
Whenever a task attempts to execute code from a non-executable page, the
PAGEEXEC or SEGMEXEC logic raises a page fault and therefore the page fault
handler is the place where EMUTRAMP can carry out its job. Since the code
to be emulated is architecture specific, EMUTRAMP is architecture dependent
as well (for now it exists for IA-32 only).
The kernel signal return stubs are generated by the kernel itself before
a signal is dispatched to the userland signal handler. There are two stubs
for returning from normal (old style) and real-time signal (new style)
handlers, respectively. By default the kernel puts all information for the
userland signal handler on the userland stack therefore the signal return
stubs end up there as well, hence the need for emulating them. It is worth
noting however that userland can tell the kernel to rely on userland
supplied signal return code (the SA_RESTORER flag) and glibc 2.1+ actually
makes use of this feature and therefore applications linking against it
do not require this emulation.
The gcc nested function trampolines implement a gcc specific C extension
where one can define a function within another one (this is the nesting).
Since the inner function has access to all the local variables of the
outer one, the compiler has to pass an extra parameter (pointer to the
outer function's stack frame) to such a nested function. This becomes a
challenge when one takes the address of the nested function and calls it
later via a function pointer (while the outer function's stack frame still
exists of course). In this case the address of the function body does not
fully identify the function since the inner function also needs access to
the outer function's stack frame. The gcc solution is that whenever the
address of a nested function is taken, gcc generates a small stub on the
stack (in the stack frame of the outer function) and uses the stub's
address as the function pointer. The stub then passes the current frame's
address to the actual inner function body. While this is pretty much the
only generic solution for implementing function pointers to nested
functions, there is a better one for a special (but likely the most often
encountered) situation: if the outer function is not called recursively
then we know that there's at most one instance of the stack frame of the
outer function and therefore its address can be stored in a normal (per
thread in case of a multithreaded program) static variable and referenced
from within the nested function's body - no need to generate the trampoline
stub at runtime.
2. Implementation
EMUTRAMP is implemented by the pax_handle_fetch_fault() function in
arch/i386/mm/fault.c. This function is called during page fault processing
when an instruction fetch attempt from a non-executable page is detected.
Each signal return stub and nested function trampoline is recognized by
checking for their instruction sequence signature and ensuring that some
additional conditions (e.g., register contents) are met as well. Emulation
itself is very simple, we only modify the userland register context which
was saved by the kernel and will be restored when it returns to userland.
The signal return stub emulation requires a bit of extra handling because
it wants to invoke a system call at the end and the task has already entered
the kernel (it is processing a page fault). Whenever EMUTRAMP is enabled,
the low-level page fault handler stub in arch/i386/kernel/entry.S can be
told to simulate a system call entry into the kernel by simply restoring
the kernel stack to the point before the page fault processing began then
jumping to the system call processing stub.