aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-02-07 14:59:04 -0800
committerColin Cross <ccross@android.com>2023-03-28 09:29:50 -0700
commit1070762ab12eac0e07db136c820815796b6acba5 (patch)
treeb2c981632fe8faf7bb14e19c6957bac6af0d6344
parent1e848dc117953f5dd8c05548219bd2c0c51ffd3f (diff)
downloadmusl-1070762ab12eac0e07db136c820815796b6acba5.tar.gz
Ignore incorrect elf architecture loaders in relinterp
In multilib systems LD_LIBRARY_PATH is sometimes set to a list that contains both the lib32 and lib64 directories, for example when running code that may execute 32-bit or 64-bit subprocesses or both. Relinterp aborts searching a path list when it finds any loader that is not loadable, preventing searching the other multilib directory. Modify relinterp to continue searching when a file is found that is a valid elf file but for an elf machine or class that differs from that of the app. Test: host-unit-tests Change-Id: Id9b9ffc0d964565d4da0db158671e5703c87c192
-rw-r--r--android/relinterp.c56
1 files changed, 46 insertions, 10 deletions
diff --git a/android/relinterp.c b/android/relinterp.c
index 5fd8ea94..d121c73b 100644
--- a/android/relinterp.c
+++ b/android/relinterp.c
@@ -125,6 +125,10 @@ static int ri_mprotect(void* addr, size_t len, int prot) {
return ri_syscall(SYS_mprotect, addr, len, prot);
}
+static ssize_t ri_pread(int fd, void* buf, size_t size, off_t ofs) {
+ return ri_syscall(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs));
+}
+
static size_t ri_strlen(const char* src) {
for (size_t len = 0;; ++len) {
if (src[len] == '\0') return len;
@@ -647,7 +651,7 @@ static void realpath_fd(int fd, const char* orig_path, char* out, size_t len) {
if ((size_t)result >= len) fatal("realpath of %s too long", orig_path);
}
-static int open_loader(const char* path, OpenedLoader* loader) {
+static int open_loader(const ExeInfo* exe, const char* path, OpenedLoader* loader) {
debug("trying to open '%s'", path);
loader->fd = ri_open(path, O_RDONLY, 0);
if (loader->fd < 0) {
@@ -655,12 +659,43 @@ static int open_loader(const char* path, OpenedLoader* loader) {
return -1;
}
+ ElfW(Ehdr) hdr;
+ ssize_t l = ri_pread(loader->fd, &hdr, sizeof(hdr), 0);
+ if (l < 0) {
+ debug("reading elf header from %s failed: %s", path, ri_strerror(g_errno));
+ return -1;
+ }
+ if (l != sizeof(hdr)) {
+ debug("file %s too short to contain elf header", path);
+ return -1;
+ }
+
+ if (hdr.e_ident[0] != ELFMAG0 ||
+ hdr.e_ident[1] != ELFMAG1 ||
+ hdr.e_ident[2] != ELFMAG2 ||
+ hdr.e_ident[3] != ELFMAG3) {
+ debug("file %s is not an elf file", path);
+ return -1;
+ }
+
+ if (hdr.e_machine != exe->ehdr->e_machine) {
+ debug("incorrect elf machine for loader %s, expected %d got %d",
+ path, exe->ehdr->e_machine, hdr.e_machine);
+ return -1;
+ }
+
+ if (hdr.e_ident[EI_CLASS] != exe->ehdr->e_ident[EI_CLASS]) {
+ debug("incorrect elf class for loader %s, expected %d got %d",
+ path, exe->ehdr->e_ident[EI_CLASS], hdr.e_ident[EI_CLASS]);
+ return -1;
+ }
+
realpath_fd(loader->fd, path, loader->path, sizeof(loader->path));
return 0;
}
-static int open_rel_loader(const char* dir, const char* rel, OpenedLoader* loader) {
+static int open_rel_loader(const ExeInfo* exe, const char* dir, const char* rel, OpenedLoader* loader) {
char buf[PATH_MAX];
size_t dir_len = ri_strlen(dir);
@@ -680,7 +715,7 @@ static int open_rel_loader(const char* dir, const char* rel, OpenedLoader* loade
}
ri_strcat(buf, rel);
- return open_loader(buf, loader);
+ return open_loader(exe, buf, loader);
}
static void get_origin(char* buf, size_t buf_len) {
@@ -693,7 +728,7 @@ static void get_origin(char* buf, size_t buf_len) {
ri_dirname(buf);
}
-static int search_path_list_for_loader(const char* loader_rel_path, const char* search_path,
+static int search_path_list_for_loader(const ExeInfo* exe, const char* loader_rel_path, const char* search_path,
const char* search_path_name, bool expand_origin, OpenedLoader *loader) {
char origin_buf[PATH_MAX];
char* origin = NULL;
@@ -743,11 +778,12 @@ static int search_path_list_for_loader(const char* loader_rel_path, const char*
ri_strcat(buf, origin);
ri_strcat(buf, d+s);
- debug("trying loader %s at %s", loader_rel_path, buf);
} else {
ri_strcpy(buf, search_path_entry);
}
- if (!open_rel_loader(buf, loader_rel_path, loader)) {
+ debug("trying loader %s at %s", loader_rel_path, buf);
+ if (!open_rel_loader(exe, buf, loader_rel_path, loader)) {
+ debug("opened loader %s at %s", loader_rel_path, buf);
return 0;
}
}
@@ -759,14 +795,14 @@ static int find_and_open_loader(const ExeInfo* exe, const char* ld_library_path,
const char* loader_rel_path = LOADER_PATH;
if (loader_rel_path[0] == '/') {
- return open_loader(loader_rel_path, loader);
+ return open_loader(exe, loader_rel_path, loader);
}
if (exe->secure) {
fatal("relinterp not supported for secure executables");
}
- if (!search_path_list_for_loader(loader_rel_path, ld_library_path, "LD_LIBRARY_PATH", false, loader)) {
+ if (!search_path_list_for_loader(exe, loader_rel_path, ld_library_path, "LD_LIBRARY_PATH", false, loader)) {
return 0;
}
@@ -774,10 +810,10 @@ static int find_and_open_loader(const ExeInfo* exe, const char* ld_library_path,
// If no DT_RUNPATH search relative to the exe.
char origin[PATH_MAX];
get_origin(origin, sizeof(origin));
- return open_rel_loader(origin, loader_rel_path, loader);
+ return open_rel_loader(exe, origin, loader_rel_path, loader);
}
- if (!search_path_list_for_loader(loader_rel_path, exe->search_paths, "rpath", true, loader)) {
+ if (!search_path_list_for_loader(exe, loader_rel_path, exe->search_paths, "rpath", true, loader)) {
return 0;
}