Repository navigation
Apply relocs for ifuncs - #1536
kStor2poche wants to merge 14 commits into
Conversation
| addr_symb = loc_db.get_name_offset(symbol_entry.name.decode()) | ||
| if addr_symb is None: | ||
| log.warning("Unable to find symbol %r" % symbol_entry.name) | ||
| log.warning("Unable to find symbol %r" % symbol_entry.name.decode()) |
There was a problem hiding this comment.
Since we're at it, just like you did further down, might as well switch to an f-string
There was a problem hiding this comment.
since it's a logger, we can also keep the %r syntax and put the name as an argument
There was a problem hiding this comment.
Sure, I switched to f-strings right now but if you feel like % encoded in logs is more idiomatic in this project I can to that too !
|
And a more general comment, maybe we should hide this behind a parameter like We also need a test, as it needs quite realistic examples, might as well add a full on script in |
| myjit.init_stack() | ||
| base_addr = 0x400000 | ||
|
|
||
| reloc_options = RelocOptions(run_ifuncs=True, ifunc_jitter_engine=args.jitter) |
There was a problem hiding this comment.
run_ifuncs=True -> I think this is a typo, you might want to use the function argument
| with open(args.filename, 'rb') as f: | ||
| elf: ContainerELF = Container.from_stream(f, addr=base_addr, loc_db=loc_db, vm=myjit.vm, apply_reloc=True, reloc_options=reloc_options) | ||
| assert isinstance(elf, ContainerELF) | ||
| if elf.executable.Ehdr.type == ET_EXEC: |
There was a problem hiding this comment.
Maybe clearer in the example if regrouped with the original definition of the base address ? (line 21)
Maybe it can be passed as an argument and put the if statement in the main ?
There was a problem hiding this comment.
I'm good with the first change but I'm not sure about the second since it would lead to unnecessarily duplicated code
|
|
||
| if args.verbose >= 2: | ||
| jitter.set_trace_log(True, True) | ||
| run_at = jitter.lifter.loc_db.get_name_offset("intermediate") |
There was a problem hiding this comment.
maybe find a clearer name for the symbol, if it's really not possible to have all the logic in the main
There was a problem hiding this comment.
technically, it would be possible to have all the logic in main and put a breakpoint right after the call to func with a hardcoded address which might be fine for our example.
I could also try to use the .got.plt entry for the relocation to directly execute what the resolved ifunc it points to but no symbol contains that value so it's a bit akward to retrieve.
In the end I find it more elegant and easily understandable to have a wrapper (and then wrapper might be a more appropriate name for the function) for that but that's just my opinion.
| @apply_reloc (optional): if set, apply relocation during ELF loading | ||
| @reloc_options (optional): see miasm.jitter.loader.elf.RelocOptions | ||
|
|
||
| @addr and @apply_reloc are only meaningful in the context of a |
| # Build the bin_stream instance and set the entry point | ||
| try: | ||
| self._bin_stream = bin_stream_elf(self._executable) | ||
| if self._executable.Ehdr.type == ET_EXEC: |
There was a problem hiding this comment.
Why not sooner in the function ? Also the warning can only show up if addr is actually not 0.
| def __init__(self, run_ifuncs: bool = False, ifunc_jitter_engine: Literal["python", "gcc", "llvm"] | None = None, ifunc_jitter = None) -> None: | ||
| """@run_ifuncs: whether or not to run, resolve and apply ifuncs | ||
| @ifunc_jitter_engine: set to "gcc" by default, unless @ifunc_jitter is used. The engine to use for the default ifunc jitter. | ||
| @ifunc_jitter: a user-provided jitter to run/resolve ifuncs with. Needs to have an initialized stack. Overrides the default ifunc jitter. |
There was a problem hiding this comment.
Needs to have an initialized stack
Maybe add "usually" ? Theoretically an ifunc resolver could be a function not using the stack ?
There was a problem hiding this comment.
This is actually needed regardless of the resolver using the stack since we create a fake stack frame for our function with 0x1337beef as our saved pc and breakpoint in order to run the resolver and gather its result in apply_reloc_x86.
| reloc_options = RelocOptions() | ||
|
|
||
| if reloc_options.run_ifuncs and elf.Ehdr.type == elf_csts.ET_EXEC: | ||
| log.warning("Running ifuncs as a part of the loading process is only accurate for dynamically-linked executables, as they are normally ran during glibc initialization for static and static-pie executables. See https://sourceware.org/glibc/manual/latest/html_node/Indirect-Functions.html#When-IFUNC-Resolvers-Run.") |
There was a problem hiding this comment.
Maybe we can cite something more "timeproof" as well ?
Like "GNU C Library Reference Manual, version 2.44, chapter/section 37.4.2 When IFUNC Resolvers Run"
|
|
||
| return elf | ||
|
|
||
| def get_ifuncs(elf, base_addr, with_syms=False): |
There was a problem hiding this comment.
I think the following 3 functions are x86 (32/64) specific. Maybe it should be mentioned in their name, the same way apply_reloc_x86 is specific about it.
| def _resolve_ifunc(reloc_addr, resolver_addr, elf, run_jitter): | ||
| """ | ||
| WARNING: this is only accurate for dynamically-linked binaries. Static and static-pie executables' ifuncs are loaded at runtime during glibc initialization. | ||
| WARNING: this requires the jitter to have an initialized stack |
| def apply_ifunc(reloc_addr, resolver_addr, elf, jitter, run_jitter=None): | ||
| """ | ||
| WARNING: this is only accurate for dynamically-linked binaries. Static and static-pie executables' ifuncs are loaded at runtime during glibc initialization. | ||
| WARNING: this requires the jitter or run_jitter (if present) to have an initialized stack |
0b82e67 to
545fb49
Compare
This implements ifunc relocation for ELFs containing them by running the ifunc on a jitter that copies the currently-being-loaded file's memory.
While this should technically be the job of the libc init functions, it made sense for my application to apply this relocation along with the other types of relocation.
This only works for ifuncs in statically and dynamically loaded executables, as per the glibc manual.
As it is a bit intensive, it could make sense to put it behind a separate option in
vm_load_eld, this is up for debate.