JonathanSalwan/ROPgadget

elf | tool treats whole segment as executable even if sections inside it are read-only

Kristal-g opened this issue · 5 comments

Great tool!

I was surprised at first when I tried to use gadgets that it found, but they were in memory that is not executable or is already freed.
The cause for this is this commit here.

I get that it might be generally more correct to search by segment and not by sections, but it could be useful to have the ability to control that feature, or maybe alert about non-executable sections inside an executable segment.

The use-case for me is searching gadgets in the linux kernel, that has a RWX segment with ".init" sections that get freed after the kernel's initialization:

Section Headers:                                                 
  [Nr] Name              Type             Address           Offset                                                                       
       Size              EntSize          Flags  Link  Info  Align                                                                       
  [ 0]                   NULL             0000000000000000  00000000 
       0000000000000000  0000000000000000           0     0     0
...
 [23] .init.data        PROGBITS         ffffffff83746000  02b46000
       00000000001eb8c0  0000000000000000  WA       0     0     8192
...
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000200000 0xffffffff81000000 0x0000000001000000
                 0x00000000020e17a8 0x00000000020e17a8  R E    0x200000
  LOAD           0x0000000002400000 0xffffffff83200000 0x0000000003200000
                 0x0000000000449000 0x0000000000449000  RW     0x200000
  LOAD           0x0000000002a00000 0x0000000000000000 0x0000000003649000
                 0x0000000000036000 0x0000000000036000  RW     0x200000
  LOAD           0x0000000002a7f000 0xffffffff8367f000 0x000000000367f000
                 0x0000000001b81000 0x0000000001b81000  RWE    0x200000
  NOTE           0x0000000001d5d5fc 0xffffffff82b5d5fc 0x0000000002b5d5fc
                 0x00000000000001d8 0x00000000000001d8         0x4

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata .pci_fixup .tracedata __ksymtab __ksymtab_gpl __kcrctab __kcrctab_gpl __ksymtab_strings __init_rodata __param __modver __ex_table .notes .BTF .BTF_ids 
   01     .data __bug_table .vvar 
   02     .data..percpu 
   03     .init.text .altinstr_aux .init.data .x86_cpu_dev.init .parainstructions .retpoline_sites .return_sites .call_sites .altinstructions .altinstr_replacement .apicdrivers .exit.text .smp_locks .data_nosave .bss .brk .init.scratch 
   04     .notes 

I would create a pull request myself, but we should first agree if we want to fix it, and how :)

@Kristal-g, I suppose we may use segments to preliminary detect memory regions for gadget search. Then, we may exclude non-executable memory areas based on sections information.

@JonathanSalwan, what do you think? What was the original cause of switching from sections to segments?

@Kristal-g, as current workaround ROPgadget has range option:

--range <start-end>   Search between two addresses (0x...-0x...)

I don't remember why we did this move =/. However, maybe we can add options to exclude sections/segments?

I took a look at other rop gadgets tools and found that some use only the sections, and some use the segments; so there's no consensus out there.
Maybe we should add a flag such as "--elfUseSections" that would be False by default, but when it's used it will make getExecSections return sections instead of segments?

I suggest either a flag like that or some warning where the addresses of the sections don't fill the whole segments (meaning that perhaps part of the segment's memory isn't meant to be executable and won't stay that way).

As I stated earlier, you may use both segments and sections. Just exclude non-executable memory areas from segments according to info in sections.