diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -90,6 +90,10 @@ ${PROG_FULL}: ${VERSION_MAP} .include +.if ${MK_SHLIBRANDOM} != "no" +CFLAGS+= -DSHLIBRANDOM +.endif + .if ${COMPILER_TYPE} == "gcc" # GCC warns about redeclarations even though they have __exported # and are therefore not identical to the ones from the system headers. diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -141,6 +141,9 @@ static int parse_integer(const char *); static void *path_enumerate(const char *, path_enum_proc, const char *, void *); static void print_usage(const char *argv0); +#if defined(SHLIBRANDOM) +static void randomize_neededs(Obj_Entry *, int); +#endif static void release_object(Obj_Entry *); static int relocate_object_dag(Obj_Entry *root, bool bind_now, Obj_Entry *rtldobj, int flags, RtldLockState *lockstate); @@ -2448,6 +2451,57 @@ return (0); } +#if defined(SHLIBRANDOM) +static void +randomize_neededs(Obj_Entry *obj, int flags) +{ + Needed_Entry **needs=NULL, *need=NULL; + unsigned int i, j, nneed; + size_t sz = sizeof(unsigned int); + int mib[2]; + + if (!(obj->needed) || (flags & RTLD_LO_FILTEES)) + return; + + mib[0] = CTL_KERN; + mib[1] = KERN_ARND; + + for (nneed = 0, need = obj->needed; need != NULL; need = need->next) + nneed++; + + if (nneed > 1) { + needs = xcalloc(nneed, sizeof(Needed_Entry **)); + for (i = 0, need = obj->needed; i < nneed; i++, need = need->next) + needs[i] = need; + + for (i=0; i < nneed; i++) { + do { + if (sysctl(mib, 2, &j, &sz, NULL, 0)) + goto err; + + j %= nneed; + } while (j == i); + + need = needs[i]; + needs[i] = needs[j]; + needs[j] = need; + } + + for (i=0; i < nneed; i++) + needs[i]->next = i + 1 < nneed ? needs[i + 1] : NULL; + + obj->needed = needs[0]; + } + +err: + if (needs != NULL) + free(needs); + + return; +} +#endif + + /* * Given a shared object, traverse its list of needed objects, and load * each of them. Returns 0 on success. Generates an error message and @@ -2461,6 +2515,9 @@ for (obj = first; obj != NULL; obj = TAILQ_NEXT(obj, next)) { if (obj->marker) continue; +#if defined(SHLIBRANDOM) + randomize_neededs(obj, flags); +#endif if (process_needed(obj, obj->needed, flags) == -1) return (-1); } diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -212,6 +212,7 @@ OPENLDAP \ REPRODUCIBLE_BUILD \ RPCBIND_WARMSTART_SUPPORT \ + SHLIBRANDOM \ SORT_THREADS \ SVN \ ZONEINFO_LEAPSECONDS_SUPPORT \ diff --git a/tools/build/options/WITH_SHLIBRANDOM b/tools/build/options/WITH_SHLIBRANDOM new file mode 100644 --- /dev/null +++ b/tools/build/options/WITH_SHLIBRANDOM @@ -0,0 +1 @@ +Enable randomizing the load order of shared objects.