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.

127 lines
8.0 KiB

  1. 1. Design
  2. The goal of RANDEXEC is to introduce randomness into the main executable
  3. file mapping addresses.
  4. While RANDMMAP takes care of randomizing ELF executables of the ET_DYN
  5. kind, a special approach is needed for randomizing the position of ET_EXEC
  6. ELF executables. As far as randomization is concerned the fundamental
  7. difference between the two kinds of ELF files is the lack/presence of
  8. adequate relocation information. Traditionally ET_EXEC files are created
  9. by the linker with the assumption that they will be loaded at a fixed
  10. address and hence relocation information is superfluous and mostly omitted.
  11. It is worth noting though that ld from the GNU binutils package can be told
  12. to emit full relocation information into ET_EXEC files, but this is a
  13. relatively new and not widely (if at all) used feature.
  14. To understand the technique that allows randomization even without enough
  15. relocation information, consider what can happen when such an ET_EXEC file
  16. is mapped into memory at an address other than its expected base address
  17. (0x08048000 on i386). As soon as the CPU attempts to execute an instruction
  18. (e.g., because of an absolute jump) or access data at the original address,
  19. it will encounter a page fault (provided there is no other mapping at those
  20. addresses). To avoid these page faults, we have to provide a file mapping
  21. of the ET_EXEC file at the original base address as well.
  22. This is not enough however for two reasons. First, the code may make data
  23. accesses in a position independent manner (e.g., the various crt*.o files
  24. linked into an executable contain such code) so we would have to ensure
  25. that the two file mappings are mirroring each other's content all the time.
  26. Second, we cannot allow the text segment mapping at the original base
  27. address to remain executable, since that would defeat the very purpose of
  28. randomization (there should be no executable code at a predictable/known
  29. address in the task's address space). However the text segment must be
  30. available for data accesses since the code may very well contain data
  31. references to absolute addresses (which would point back to the original
  32. mapping).
  33. So the next refinement of our technique is that we will create two mappings
  34. of the ET_EXEC file that will mirror each other, the first one at its
  35. original base address and the second at a randomized one and we ensure that
  36. the original mappings are not executable.
  37. There is one last feature missing: since the code may attempt to execute
  38. from the original and now non-executable mapping, it will produce extra
  39. page faults that will need special handling. In particular, whenever we
  40. detect a page fault due to an instruction fetch attempt in such a region,
  41. we will redirect the execution flow back into the randomized mirror by
  42. simply modifying the userland instruction pointer. Since automatic
  43. redirection would again defeat the purpose of randomization, we can do
  44. various checks in the page fault handler before we decide to go ahead with
  45. the redirection. In the current implementation we attempt to detect so
  46. called return-to-libc style attacks against the ET_EXEC mapping by checking
  47. the userland stack for its signature. Since such a signature may (and does)
  48. occur due to normal program code as well, this detection can (and does)
  49. produce false alarms (that is, it can kill an innocent task), however it
  50. will never miss the attack attempt it was designed to detect.
  51. Now that the basic RANDEXEC technique is clear, let's see how it is affected
  52. by SEGMEXEC. Under SEGMEXEC the executable status of a page is expressed by
  53. not its page protection flags but its location in linear address space.
  54. That is, executable regions have to be mirrored. Since RANDEXEC itself needs
  55. mirroring, one may wonder how the triple mirroring for the ET_EXEC file's
  56. text section can be accomplished (the current vma mirroring implementation
  57. supports only the simplest mirroring setup, that is two regions mirroring
  58. each other). The triple mirroring would be needed because we have the
  59. original and the randomized mapping in the data segment region (0-1.5 GB in
  60. linear address space) plus we need the third one in the code segment region
  61. (1.5-3 GB in linear address space). However consider if we really need the
  62. randomized mapping of the file's text section in the data segment region.
  63. Such data accesses could occur only if there was position independent code
  64. in the executable that would learn its own position in memory then use that
  65. to access data stored in the text section. In most real life applications
  66. no such code exists, simply because programs are compiled/linked under the
  67. assumption that they will be executed at a fixed/known address therefore
  68. there is no need for position independence (exceptions are incorrectly
  69. linked programs where a position independent library is statically linked
  70. into the executable, such as the Modula-3 runtime in CVSup). This leaves
  71. us now with just two mappings which the vma mirroring system supports well.
  72. 2. Implementation
  73. The core of RANDEXEC is vma mirroring which is discussed in a separate
  74. document. The mirrors for the ET_EXEC file segments are set up in the
  75. load_elf_binary() function in fs/binfmt_elf.c. The mirrors are created
  76. differently depending on which of PAGEEXEC/SEGMEXEC is active.
  77. The PAGEEXEC logic: every ELF segment is mapped as non-executable at its
  78. original base address and the mirrors are created at a random address
  79. returned by get_unmapped_area(). This also means that they will be using
  80. the same randomization that other mmap() requests see.
  81. The SEGMEXEC logic: the mappings at the original base address are mapped
  82. as normal (no need for removing PROT_EXEC from the requests since they will
  83. go into the data segment region anyway) with a little change: instead of
  84. using elf_map() we directly use do_mmap_pgoff(). This is because elf_map()
  85. is a wrapper around do_mmap() which in turn would attempt to create the
  86. normal SEGMEXEC mirrors and is not suitable here since we need to position
  87. the mirrors in a different way. As under PAGEEXEC, get_unmapped_area() is
  88. used to get a random address where the ELF segment mirrors will be mapped.
  89. The difference is in the mapping of executable mirrors: they will go into
  90. the code segment region (1.5-3 GB linear address range) and in the data
  91. segment (0-1.5 GB range) at the same logical addresses we create dummy
  92. anonymous mappings as placeholders (otherwise there would be holes in the
  93. data segment which the kernel later would try to use for mapping the ELF
  94. interpreter and that could potentially unmap our randomized mirrors).
  95. The extra page fault handling and execution flow redirection happens in
  96. the archictecture specific low-level page fault handlers, for now it exists
  97. for the i386 architecture only. When the do_page_fault() or the
  98. pax_do_page_fault() functions in arch/i386/mm/fault.c detect an instruction
  99. fetch attempt (that is, when the fault address is equal to the faulting EIP)
  100. then pax_handle_fetch_fault() will examine if the fault occured within the
  101. main executable's code segment. If it did then we take a look at just below
  102. the current userland stack pointer (ESP-4) to see if it contains the address
  103. of the fault location. If it does, we declare it as a return-to-libc style
  104. attack attempt and terminate the task, otherwise we readjust the userland
  105. EIP to point back to the randomized mirror region and return to userland.
  106. Note that this check works for detecting attacks where control flow was
  107. changed by a 'retn' instruction (this is the normal way of returning from
  108. a function as the caller is expected to adjust the stack), other forms
  109. ('retf' or 'retn xx') would need more, slightly different verification (as
  110. they modify the ESP register by more than 4, we would have to check more
  111. below ESP at the expense of increasing the false positive ratio).