From 568b8075a4406ca8cb1f718e74fd0829cb7f0b90 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sat, 25 Jun 2011 01:56:34 -0400 Subject: [PATCH] proper path searching for dynamic linker first, use $LD_LIBRARY_PATH unless suid. if that fails, read path from /etc/ld-musl-$ARCH.path and fallback to a builtin default. --- arch/i386/reloc.h | 2 ++ arch/x86_64/reloc.h | 2 ++ src/ldso/dynlink.c | 52 +++++++++++++++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/arch/i386/reloc.h b/arch/i386/reloc.h index 02b5fa02..3ca9d11d 100644 --- a/arch/i386/reloc.h +++ b/arch/i386/reloc.h @@ -1,6 +1,8 @@ #include #include +#define ETC_LDSO_PATH "/etc/ld-musl-i386.path" + #define IS_COPY(x) ((x)==R_386_COPY) static inline void do_single_reloc(size_t *reloc_addr, int type, size_t sym_val, size_t sym_size, unsigned char *base_addr, size_t addend) diff --git a/arch/x86_64/reloc.h b/arch/x86_64/reloc.h index 2db6115d..6642fdd4 100644 --- a/arch/x86_64/reloc.h +++ b/arch/x86_64/reloc.h @@ -2,6 +2,8 @@ #include #include +#define ETC_LDSO_PATH "/etc/ld-musl-x86_64.path" + #define IS_COPY(x) ((x)==R_X86_64_COPY) static inline void do_single_reloc(size_t *reloc_addr, int type, size_t sym_val, size_t sym_size, unsigned char *base_addr, size_t addend) diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 105ed3d7..f57485da 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -48,7 +48,7 @@ struct dso }; static struct dso *head, *tail, *libc; -static int trust_env; +static char *env_path, *sys_path; #define AUX_CNT 15 #define DYN_CNT 34 @@ -205,6 +205,20 @@ static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dy return map; } +static int path_open(const char *name, const char *search) +{ + char buf[2*NAME_MAX+2]; + const char *s, *z; + int l, fd; + for (s=search; *s; s+=l+!!z) { + z = strchr(s, ':'); + l = z ? z-s : strlen(s); + snprintf(buf, sizeof buf, "%.*s/%s", l, s, name); + if ((fd = open(buf, O_RDONLY))>=0) return fd; + } + return -1; +} + static struct dso *load_library(const char *name) { unsigned char *base, *map; @@ -242,14 +256,20 @@ static struct dso *load_library(const char *name) if (name[0] == '/') { fd = open(name, O_RDONLY); } else { - static const char path[] = "/lib/\0/usr/local/lib/\0/usr/lib/\0"; - const char *s; - char buf[NAME_MAX+32]; if (strlen(name) > NAME_MAX || strchr(name, '/')) return 0; - for (s=path; *s; s+=strlen(s)+1) { - strcpy(buf, s); - strcat(buf, name); - if ((fd = open(buf, O_RDONLY))>=0) break; + fd = -1; + if (env_path) fd = path_open(name, env_path); + if (fd < 0) { + if (!sys_path) { + FILE *f = fopen(ETC_LDSO_PATH, "r"); + if (f) { + if (getline(&sys_path, (size_t[1]){0}, f) > 0) + sys_path[strlen(sys_path)-1]=0; + fclose(f); + } + } + if (sys_path) fd = path_open(name, sys_path); + else fd = path_open(name, "/lib:/usr/local/lib:/usr/lib"); } } if (fd < 0) return 0; @@ -342,11 +362,19 @@ void *__dynlink(int argc, char **argv, size_t *got) struct dso lib, app; /* Find aux vector just past environ[] */ - for (i=argc+1; argv[i]; i++); + for (i=argc+1; argv[i]; i++) + if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16)) + env_path = argv[i]+16; auxv = (void *)(argv+i+1); decode_vec(auxv, aux, AUX_CNT); + /* Only trust user/env if kernel says we're not suid/sgid */ + if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] + || aux[AT_GID]!=aux[AT_EGID]) { + env_path = 0; + } + /* Relocate ldso's DYNAMIC pointer and load vector */ decode_vec((void *)(got[0] += aux[AT_BASE]), lib_dyn, DYN_CNT); @@ -385,11 +413,6 @@ void *__dynlink(int argc, char **argv, size_t *got) /* At this point the standard library is fully functional */ - /* Only trust user/env if kernel says we're not suid/sgid */ - trust_env = (aux[0]&0x7800)==0x7800 - && aux[AT_UID]==aux[AT_EUID] - && aux[AT_GID]==aux[AT_EGID]; - head = tail = &app; libc = &lib; app.next = 0; @@ -398,6 +421,7 @@ void *__dynlink(int argc, char **argv, size_t *got) reloc_all(head); free_all(head); + free(sys_path); errno = 0; return (void *)aux[AT_ENTRY]; -- 2.20.1