I am trying to understand the difference in the mechanisms underlying load-time linking (using gcc -l
) versus run-time linking (using dlopen(), dlsym()
) of dynamic libraries in Linux, and how these mechanisms affect the state of the library and the addresses of its symbols.
The experiment
I have three simple files:
libhello.c:
int var;
int func() {
return 7;
}
libhello.h:
extern int var;
int func();
main.c:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include "libhello.h"
int main() {
void* h = dlopen("libhello.so", RTLD_NOW);
printf("Address Load-time linking Run-time linking\n");
printf("------- ----------------- ----------------\n");
printf("&var 0x%016" PRIxPTR " 0x%016" PRIxPTR "\n", (uintptr_t)&var , (uintptr_t)dlsym(h, "var" ));
printf("&func 0x%016" PRIxPTR " 0x%016" PRIxPTR "\n", (uintptr_t)&func, (uintptr_t)dlsym(h, "func"));
}
I compile libhello.c with the command gcc -shared -o libhello.so -fPIC libhello.c
I compile main.c with the command gcc main.c -L. -lhello -ldl
The observation
Running the main.c executable prints something like this:
Address Load-time linking Run-time linking
------- ----------------- ----------------
&var 0x0000000000601060 0x00007fdb4acb1034
&func 0x0000000000400700 0x00007fdb4aab0695
The load-time linking addresses remain the same, but the run-time linking addresses change every run.
The questions
- Why do the run-time addresses change every run? Do they change due to Address space layout randomization?
- If this is the case, why don't addresses change for load-time linking? Isn't load-time linking vulnerable to the same attacks that address randomization aims to protect against?
- In the above program, the same library is loaded twice - once at load-time and then at run-time using
dlopen()
. The second load does not copy the state of the first load. I.e. if the value ofvar
is changed beforedlopen()
, this value isn't reflected in the version ofvar
loaded viadlsym()
. Is there any way to retain this state during the second load?
randomize_va_space = 2
. – Dupondiusgcc -o main main.c -L. -lhello -ldl -Wl,-rpath $(pwd -L)
– Montegcc -o main main.c -L. -lhello -ldl -Wl,-brtl,-blibpath:$(pwd -L):/usr/lib
– Monte