Skip to content

Commit

Permalink
Fix "failed to find __libc_dlopen_mode in the .dynstr section" when t…
Browse files Browse the repository at this point in the history
…he libc is glibc 2.34 or later.

__libc_dlopen_mode in libc was removed and dlopen was moved from libdl.so.2 to libc.so.6 in glibc 2.34.
  • Loading branch information
kubo committed Feb 19, 2022
1 parent 183b476 commit 5f77f11
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 8 deletions.
29 changes: 22 additions & 7 deletions src/linux/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ int injector__collect_libc_information(injector_t *injector)
size_t str_size = 0;
size_t sym_offset = 0;
size_t sym_num = 0;
int use_internal_dlfunc = 0;
size_t sym_entsize = 0;
size_t dlopen_st_name;
size_t dlopen_offset;
Expand Down Expand Up @@ -124,9 +125,14 @@ int injector__collect_libc_information(injector_t *injector)
goto cleanup;
}

dlopen_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlopen_mode");
dlopen_st_name = find_strtab_offset(fp, str_offset, str_size, "dlopen");
if (dlopen_st_name == 0) {
injector__set_errmsg("failed to find __libc_dlopen_mode in the .dynstr section.");
/* glibc 2.33 or earlier */
use_internal_dlfunc = 1;
dlopen_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlopen_mode");
}
if (dlopen_st_name == 0) {
injector__set_errmsg("failed to find dlopen/__libc_dlopen_mode in the .dynstr section.");
rv = INJERR_NO_FUNCTION;
goto cleanup;
}
Expand All @@ -143,9 +149,13 @@ int injector__collect_libc_information(injector_t *injector)
}
}

dlclose_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlclose");
if (!use_internal_dlfunc) {
dlclose_st_name = find_strtab_offset(fp, str_offset, str_size, "dlclose");
} else {
dlclose_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlclose");
}
if (dlclose_st_name == 0) {
injector__set_errmsg("failed to find __libc_dlclose in the .dynstr section.");
injector__set_errmsg("failed to find dlclose/__libc_dlclose in the .dynstr section.");
rv = INJERR_NO_FUNCTION;
goto cleanup;
}
Expand All @@ -161,10 +171,14 @@ int injector__collect_libc_information(injector_t *injector)
break;
}
}

dlsym_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlsym");

if (!use_internal_dlfunc) {
dlsym_st_name = find_strtab_offset(fp, str_offset, str_size, "dlsym");
} else {
dlsym_st_name = find_strtab_offset(fp, str_offset, str_size, "__libc_dlsym");
}
if (dlsym_st_name == 0) {
injector__set_errmsg("failed to find __libc_dlsym in the .dynstr section.");
injector__set_errmsg("failed to find dlsym/__libc_dlsym in the .dynstr section.");
rv = INJERR_NO_FUNCTION;
goto cleanup;
}
Expand All @@ -181,6 +195,7 @@ int injector__collect_libc_information(injector_t *injector)
}
}

injector->use_internal_dlfunc = use_internal_dlfunc;
injector->dlopen_addr = libc_addr + dlopen_offset;
injector->dlclose_addr = libc_addr + dlclose_offset;
injector->dlsym_addr = libc_addr + dlsym_offset;
Expand Down
6 changes: 5 additions & 1 deletion src/linux/injector.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ int injector_attach(injector_t **injector_out, pid_t pid)
int injector_inject(injector_t *injector, const char *path, void **handle)
{
char abspath[PATH_MAX];
int dlflags = RTLD_LAZY;
size_t len;
int rv;
long retval;
Expand All @@ -136,8 +137,11 @@ int injector_inject(injector_t *injector, const char *path, void **handle)
if (rv != 0) {
return rv;
}
if (injector->use_internal_dlfunc) {
#define __RTLD_DLOPEN 0x80000000 // glibc internal flag
rv = injector__call_function(injector, &retval, injector->dlopen_addr, injector->text, RTLD_LAZY | __RTLD_DLOPEN);
dlflags |= __RTLD_DLOPEN;
}
rv = injector__call_function(injector, &retval, injector->dlopen_addr, injector->text, dlflags);
if (rv != 0) {
return rv;
}
Expand Down
1 change: 1 addition & 0 deletions src/linux/injector_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct injector {
uint8_t mmapped;
arch_t arch;
struct user_regs_struct regs;
int use_internal_dlfunc; /* true if glibc 2.33 or earlier */
size_t dlopen_addr;
size_t dlclose_addr;
size_t dlsym_addr;
Expand Down

0 comments on commit 5f77f11

Please sign in to comment.