diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-03-30 03:11:45 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-03-30 03:11:45 +0000 |
commit | ce44f260fc081625ef6693fa233e5549aa8b4de2 (patch) | |
tree | 28523674f3e6fad32dbec47e22b3ba1d223b80eb | |
parent | 7a5b0ab3a1ed5bd40c639c91ee78f0340d138d18 (diff) | |
parent | e8035c3f686db07475eb947494e2d5765c33c958 (diff) | |
download | musl-android14-platform-release.tar.gz |
Snap for 9849129 from e8035c3f686db07475eb947494e2d5765c33c958 to udc-releaseandroid-vts-14.0_r4android-vts-14.0_r3android-vts-14.0_r2android-vts-14.0_r1android-security-14.0.0_r8android-security-14.0.0_r7android-security-14.0.0_r6android-security-14.0.0_r5android-security-14.0.0_r4android-security-14.0.0_r3android-security-14.0.0_r2android-security-14.0.0_r1android-platform-14.0.0_r7android-platform-14.0.0_r6android-platform-14.0.0_r5android-platform-14.0.0_r4android-platform-14.0.0_r3android-platform-14.0.0_r2android-platform-14.0.0_r1android-cts-14.0_r4android-cts-14.0_r3android-cts-14.0_r2android-cts-14.0_r1android-14.0.0_r28android-14.0.0_r2android-14.0.0_r15android-14.0.0_r14android-14.0.0_r13android-14.0.0_r1android14-tests-releaseandroid14-security-releaseandroid14-s2-releaseandroid14-s1-releaseandroid14-releaseandroid14-platform-release
Change-Id: Ie2564850182a85b32e2d5ede910715565e3d1484
-rw-r--r-- | android/relinterp.c | 57 | ||||
-rw-r--r-- | ldso/dynlink.c | 77 | ||||
-rw-r--r-- | src/misc/getopt.c | 4 | ||||
-rw-r--r-- | src/misc/getopt_long.c | 21 |
4 files changed, 129 insertions, 30 deletions
diff --git a/android/relinterp.c b/android/relinterp.c index 5fd8ea94..c900e79c 100644 --- a/android/relinterp.c +++ b/android/relinterp.c @@ -26,6 +26,7 @@ * SUCH DAMAGE. */ +#define SYSCALL_NO_TLS 1 #include <elf.h> #include <errno.h> #include <fcntl.h> @@ -125,6 +126,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 +652,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 +660,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 +716,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 +729,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 +779,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 +796,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 +811,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; } diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 24fe47cf..d055bd26 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -65,6 +65,8 @@ struct dso { size_t *dynv; struct dso *next, *prev; + int elfmachine; + int elfclass; Phdr *phdr; int phnum; size_t phentsize; @@ -644,6 +646,19 @@ static void unmap_library(struct dso *dso) } } +static int verify_elf_magic(const Ehdr* eh) { + return eh->e_ident[0] == ELFMAG0 && + eh->e_ident[1] == ELFMAG1 && + eh->e_ident[2] == ELFMAG2 && + eh->e_ident[3] == ELFMAG3; +} + +/* Verifies that an elf header's machine and class match the loader */ +static int verify_elf_arch(const Ehdr* eh) { + return eh->e_machine == ldso.elfmachine && + eh->e_ident[EI_CLASS] == ldso.elfclass; +} + static void *map_library(int fd, struct dso *dso) { Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)]; @@ -666,6 +681,10 @@ static void *map_library(int fd, struct dso *dso) if (l<0) return 0; if (l<sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC)) goto noexec; + if (!verify_elf_magic(eh)) goto noexec; + if (!verify_elf_arch(eh)) goto noexec; + dso->elfmachine = eh->e_machine; + dso->elfclass = eh->e_ident[EI_CLASS]; phsize = eh->e_phentsize * eh->e_phnum; if (phsize > sizeof buf - sizeof *eh) { allocated_buf = malloc(phsize); @@ -830,29 +849,53 @@ error: return 0; } -static int path_open(const char *name, const char *s, char *buf, size_t buf_size) +static int path_open_library(const char *name, const char *s, char *buf, size_t buf_size) { size_t l; int fd; + const char *p; for (;;) { s += strspn(s, ":\n"); + p = s; l = strcspn(s, ":\n"); if (l-1 >= INT_MAX) return -1; - if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) { - if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd; - switch (errno) { - case ENOENT: - case ENOTDIR: - case EACCES: - case ENAMETOOLONG: - break; - default: - /* Any negative value but -1 will inhibit - * futher path search. */ + s += l; + if (snprintf(buf, buf_size, "%.*s/%s", (int)l, p, name) < buf_size) { + fd = open(buf, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + case ENAMETOOLONG: + /* Keep searching in path list. */ + continue; + default: + /* Any negative value but -1 will + * inhibit further path search in + * load_library. */ + return -2; + } + } + Ehdr eh; + ssize_t n = pread(fd, &eh, sizeof eh, 0); + /* If the elf file is invalid return -2 to inhibit + * further path search in load_library. */ + if (n < 0 || + n != sizeof eh || + !verify_elf_magic(&eh)) { + close(fd); return -2; } + /* If the elf file has a valid header but is for the + * wrong architecture ignore it and keep searching the + * path list. */ + if (!verify_elf_arch(&eh)) { + close(fd); + continue; + } + return fd; } - s += l; } } @@ -1076,12 +1119,12 @@ static struct dso *load_library(const char *name, struct dso *needed_by) } if (strlen(name) > NAME_MAX) return 0; fd = -1; - if (env_path) fd = path_open(name, env_path, buf, sizeof buf); + if (env_path) fd = path_open_library(name, env_path, buf, sizeof buf); for (p=needed_by; fd == -1 && p; p=p->needed_by) { if (fixup_rpath(p, buf, sizeof buf) < 0) fd = -2; /* Inhibit further search. */ if (p->rpath) - fd = path_open(name, p->rpath, buf, sizeof buf); + fd = path_open_library(name, p->rpath, buf, sizeof buf); } if (fd == -1) { if (!sys_path) { @@ -1120,7 +1163,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by) } } if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib"; - fd = path_open(name, sys_path, buf, sizeof buf); + fd = path_open_library(name, sys_path, buf, sizeof buf); } pathname = buf; } @@ -1694,6 +1737,8 @@ hidden void __dls2(unsigned char *base, size_t *sp) ldso.phnum = ehdr->e_phnum; ldso.phdr = laddr(&ldso, ehdr->e_phoff); ldso.phentsize = ehdr->e_phentsize; + ldso.elfmachine = ehdr->e_machine; + ldso.elfclass = ehdr->e_ident[EI_CLASS]; kernel_mapped_dso(&ldso); decode_dyn(&ldso); diff --git a/src/misc/getopt.c b/src/misc/getopt.c index c3f66995..f8df7aea 100644 --- a/src/misc/getopt.c +++ b/src/misc/getopt.c @@ -25,7 +25,7 @@ void __getopt_msg(const char *a, const char *b, const char *c, size_t l) FUNLOCK(f); } -int getopt(int argc, char * const argv[], const char *optstring) +int __posix_getopt(int argc, char * const argv[], const char *optstring) { int i; wchar_t c, d; @@ -101,5 +101,3 @@ int getopt(int argc, char * const argv[], const char *optstring) } return c; } - -weak_alias(getopt, __posix_getopt); diff --git a/src/misc/getopt_long.c b/src/misc/getopt_long.c index 6949ab1c..117d1a1d 100644 --- a/src/misc/getopt_long.c +++ b/src/misc/getopt_long.c @@ -9,6 +9,8 @@ extern int __optpos, __optreset; +int __posix_getopt(int argc, char * const argv[], const char *optstring); + static void permute(char *const *argv, int dest, int src) { char **av = (char **)argv; @@ -134,7 +136,7 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring return '?'; } } - return getopt(argc, argv, optstring); + return __posix_getopt(argc, argv, optstring); } int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) @@ -146,3 +148,20 @@ int getopt_long_only(int argc, char *const *argv, const char *optstring, const s { return __getopt_long(argc, argv, optstring, longopts, idx, 1); } + +/* ANDROID CHANGE: implement getopt via getopt_long to continue parsing options + * after the first non-option argument to match the user visible behavior of + * glibc. + */ +int getopt(int argc, char * const argv[], const char *optstring) +{ + static int posixly_correct = -1; + + if (posixly_correct == -1 || __optreset) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + + if (posixly_correct) + return __posix_getopt(argc, argv, optstring); + else + return __getopt_long(argc, argv, optstring, NULL, NULL, 0); +} |