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.

74 lines
4.4 KiB

  1. 1. Design
  2. The goal of RANDKSTACK is to introduce randomness into the kernel stack
  3. addresses of a task.
  4. Linux assigns two pages of kernel stack to every task. This stack is used
  5. whenever the task enters the kernel (system call, device interrupt, CPU
  6. exception, etc). Note that once the task is executing in kernel land,
  7. further kernel (re)entry events (device interrupts or CPU exceptions can
  8. occur at almost any time) will not cause a stack switch.
  9. By the time the task returns to userland, the kernel land stack pointer
  10. will be at the point of the initial entry to the kernel (this also means
  11. that signals are not delivered to the task until it is ready to return to
  12. userland, that is signals are asynchronous notifications from the userland
  13. point of view, not from the kernel's).
  14. This behaviour means that a userland originating attack against a kernel
  15. bug would find itself always at the same place on the task's kernel stack
  16. therefore we will introduce randomization into the initial value of the
  17. task's kernel stack pointer. There is another interesting consequence in
  18. that we can not only introduce but also change the randomization at each
  19. userland/kernel transition (compare this to RANDUSTACK where the userland
  20. stack pointer is randomized only once at the very beginning of the task's
  21. life therefore it is vulnerable to information leaking attacks). In the
  22. current implementation we opted for changing the randomization at every
  23. system call since that is the most likely method of kernel entry during
  24. an attack. Note that while per system call randomization prevents making
  25. use of leaked information about the randomization in a given task, it does
  26. not help with attacks where more than one task is involved (where one task
  27. may be able to learn the randomization of another and then communicate it
  28. to the other without having to enter the kernel).
  29. 2. Implementation
  30. RANDKSTACK randomizes every task's kernel stack pointer before returning
  31. from a system call to userland. The i386 specific system call entry point
  32. is in arch/i386/kernel/entry.S and this is where PaX adds a call to the
  33. kernel stack pointer randomization function pax_randomize_kstack() found
  34. in arch/i386/kernel/process.c. The code in entry.S needs to duplicate some
  35. code found at the ret_from_sys_call label because this code can be reached
  36. from different paths (e.g., exception handlers) where we do not want to
  37. apply randomization. Note also that if the task is being debugged (via
  38. the ptrace() interface) then new randomization is not applied.
  39. pax_randomize_kstack() gathers entropy from the rdtsc instruction (read
  40. time stamp counter) and applies it to bits 2-6 of the kernel stack pointer.
  41. This means that 5 bits are randomized providing a maximum shift of 128
  42. bytes - this was deemed safe enough to not cause kernel stack overflows
  43. yet give enough randomness to deter guessing/brute forcing attempts.
  44. The use of rdtsc is justified by the facts that we need a quick entropy
  45. source and that by the time a remote attacker would get to execute his
  46. code to exploit a kernel bug, enough system calls would have been issued
  47. by the attacked process to accumulate more than 5 bits of 'real' entropy
  48. in the randomized bits (this is why xor is used to apply the rdtsc output).
  49. Note that most likely due to its microarchitecture, the Intel P4 CPU seems
  50. to always return the same value in the least significant bit of the time
  51. stamp counter therefore we ignore it in kernels compiled for the P4.
  52. The kernel stack pointer has to be modified at two places: tss->esp0 which
  53. is the ring-0 stack pointer in the Task State Segment of the current CPU
  54. (and is used to load esp on a ring transition, such as a system call), and
  55. second, current->thread.esp0 which is used to reload tss->esp0 on a context
  56. switch. There is one last subtlety: since the randomization is applied via
  57. xor and the initial kernel stack pointer of a new task points just above
  58. its assigned stack (and hence is a page aligned address), we would produce
  59. esp values pointing above the assigned stack, therefore in copy_thread() we
  60. initialize thread.esp0 to 4 bytes less than usual so that the randomization
  61. will shift it within the assigned stack and not above. Since this solution
  62. 'wastes' a mere 4 bytes on the kernel stack, we saw no need to apply it
  63. selectively to specific tasks only.