You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
4.6 KiB

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