Skip to content

Instantly share code, notes, and snippets.

@cyyself
Last active January 11, 2025 20:19
Show Gist options
  • Save cyyself/0d3b8670e0511165955725edd68a4a96 to your computer and use it in GitHub Desktop.
Save cyyself/0d3b8670e0511165955725edd68a4a96 to your computer and use it in GitHub Desktop.

We can trust the use of _dl_lookup_symbol_x during elf_machine_runtime_setup in SHARED is safe

Prove

These discussions are based on recent glibc commit a4c414796a.

I know it's hard to prove _dl_lookup_symbol_x being called at elf_machine_runtime_setup without l_relocated == 1 when we have #ifdef SHARED is safe. But if we trust another place it is being called is safe, and there is no change for the requested data structure between these 2 times , then it's natural to trust we call it here is safe.

We can prove this by debugging lib/ld-linux-riscv64-lp64d.so.1 in gdb. First, compile glibc commit a4c414796a with && l->l_relocated removed in sysdeps/riscv/dl-machines.h.

Just write a simple Hello world program in C and compile with -fpie -pie -mrelax, and run ld-linux-riscv64-lp64d.so.1 and set 2 breakpoints at _dl_lookup_symbol_x and elf_machine_runtime_setup symbols then run ld-linux with that hello world program as argv[1]. And see the first time _dl_lookup_symbol_x is called from elf_machine_runtime_setup and the next time and then compare the stack backtrace.

Specifically, we can use this gdb script:

file /PATH_TO_GLIBC_INSTALL/lib/ld-linux-riscv64-lp64d.so.1
b elf_machine_runtime_setup
r ./hello_world
c
b _dl_lookup_symbol_x
c
bt
c
bt

And we see:

Breakpoint 2, _dl_lookup_symbol_x (undef_name=undef_name@entry=0x3ff7ff5050 "__global_pointer$", undef_map=undef_map@entry=0x3ff7fff280, ref=ref@entry=0x3fffffed48, symbol_scope=0x3ff7fff5f8, version=version@entry=0x0, type_class=0,
    flags=flags@entry=0, skip_map=skip_map@entry=0x0) at dl-lookup.c:759
#0  _dl_lookup_symbol_x
#1  0x0000003ff7fe59a8 in elf_machine_runtime_setup at ../sysdeps/riscv/dl-machine.h:362
#2  _dl_relocate_object_no_relro at dl-reloc.c:296
....

Breakpoint 2, _dl_lookup_symbol_x (undef_name=0x3ff7fd3496 "__cxa_finalize", undef_map=undef_map@entry=0x3ff7fff280, ref=ref@entry=0x3fffffed40, symbol_scope=symbol_scope@entry=0x3ff7fff5f8, version=0x3ff7fd15b0, type_class=0,
    flags=flags@entry=9, skip_map=skip_map@entry=0x0) at dl-lookup.c:759
#0  _dl_lookup_symbol_x at dl-lookup.c:759
#1  0x0000003ff7fe566a in resolve_map at dl-reloc.c:190
#2  elf_machine_rela at ../sysdeps/riscv/dl-machine.h:181
#3  elf_dynamic_do_Rela at /PATH_TO_GLIBC/elf/do-rel.h:138
#4  _dl_relocate_object_no_relro at dl-reloc.c:296
...

Between these 2 breakpoints, there are no changes to undef_map and symbol_scope (not only the value of the pointer, but we can also try using single-step execution and find there is no modification to the data structure). We can trust that the second time we look at the symbol is safe, and so is the first time from elf_machine_runtime_setup.

You may ask why it does not apply to statie-pie. It's because when loading statie-pie, the RESOLVE_MAP macro will be the map directly, which can be seen from elf/dl-reloc-static-pie.c:29, hence no call to resolve_map and even no _dl_lookup_symbol_x. Such static-pie will only call _dl_lookup_symbol_x to find vdso symbols. This shows no existing use case exists for a simple static-pie to call _dl_lookup_symbol_x for itself. Thus, we can't prove the use of _dl_lookup_symbol_x in statie-pie is safe. But we have already avoided the use of this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment