aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-30 03:11:45 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-03-30 03:11:45 +0000
commitce44f260fc081625ef6693fa233e5549aa8b4de2 (patch)
tree28523674f3e6fad32dbec47e22b3ba1d223b80eb
parent7a5b0ab3a1ed5bd40c639c91ee78f0340d138d18 (diff)
parente8035c3f686db07475eb947494e2d5765c33c958 (diff)
downloadmusl-android14-platform-release.tar.gz
Change-Id: Ie2564850182a85b32e2d5ede910715565e3d1484
-rw-r--r--android/relinterp.c57
-rw-r--r--ldso/dynlink.c77
-rw-r--r--src/misc/getopt.c4
-rw-r--r--src/misc/getopt_long.c21
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);
+}