From e6f79ac951d0ba02bbc4f4e5e86b7418cde2ab59 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Fri, 3 Mar 2023 11:29:45 +0530 Subject: [PATCH] fix: crash in `postject_find_resource()` on Linux (#77) * fix: crash in `postject_find_resource()` on Linux The program headers base address values returned by `getauxval(AT_PHDR)` and `dl_iterate_phdr()` are identical only on `g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0`. However, the values are totally different on `clang version 10.0.0-4ubuntu1` and `g++ (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16)`. Since the `dl_iterate_phdr()` approach seems to work for all the 3 compilers, I think we should proceed with that. Fixes: https://github.com/nodejs/postject/issues/70 Refs: https://github.com/nodejs/postject/issues/76 Signed-off-by: Darshan Sen * chore: remove unnecessary if block Signed-off-by: Darshan Sen * fix: only iterate the main executable program headers The resource gets injected in the main executable, so there is no need to iterate the other shared libraries that are loaded by the program. This also resolves a security concern. Refs: https://github.com/nodejs/postject/pull/77#pullrequestreview-1321016158 Signed-off-by: Darshan Sen * chore: shorten change Signed-off-by: Darshan Sen * test: add comment about _GNU_SOURCE Signed-off-by: Darshan Sen --------- Signed-off-by: Darshan Sen --- postject-api.h | 20 ++++++++++++++++---- test/test.c | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/postject-api.h b/postject-api.h index 4ec1f64..875ddc3 100644 --- a/postject-api.h +++ b/postject-api.h @@ -12,7 +12,6 @@ #elif defined(__linux__) #include #include -#include #include #elif defined(_WIN32) #include @@ -44,6 +43,16 @@ static inline bool postject_has_resource() { return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1'; } +#if defined(__linux__) +static int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info, + size_t size, + void* data) { + // Snag the dl_phdr_info struct for the main program, then stop iterating + *((struct dl_phdr_info*)data) = *info; + return 1; +} +#endif + static const void* postject_find_resource( const char* name, size_t* size, @@ -114,9 +123,12 @@ static const void* postject_find_resource( name = options->elf_section_name; } - uintptr_t p = getauxval(AT_PHDR); - size_t n = getauxval(AT_PHNUM); - uintptr_t base_addr = p - sizeof(ElfW(Ehdr)); + struct dl_phdr_info main_program_info; + dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info); + + uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr; + size_t n = main_program_info.dlpi_phnum; + uintptr_t base_addr = main_program_info.dlpi_addr; // iterate program header for (; n > 0; n--, p += sizeof(ElfW(Phdr))) { diff --git a/test/test.c b/test/test.c index d1b8ff4..f957c6f 100644 --- a/test/test.c +++ b/test/test.c @@ -1,3 +1,7 @@ +#define _GNU_SOURCE // This is needed because postject-api.h uses + // dl_iterate_phdr and dl_phdr_info which are non-standard + // GNU extensions. + #include #include