summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-06-25 01:56:34 -0400
committerRich Felker <dalias@aerifal.cx>2011-06-25 01:56:34 -0400
commit568b8075a4406ca8cb1f718e74fd0829cb7f0b90 (patch)
tree0a071dabd590f6ca123cdc1c3906ef497efe8a92
parentf937031800e3130b3b4bb42d0d547bb69a5d32db (diff)
downloadmusl-568b8075a4406ca8cb1f718e74fd0829cb7f0b90.tar.gz
musl-568b8075a4406ca8cb1f718e74fd0829cb7f0b90.tar.bz2
musl-568b8075a4406ca8cb1f718e74fd0829cb7f0b90.tar.xz
musl-568b8075a4406ca8cb1f718e74fd0829cb7f0b90.zip
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.
-rw-r--r--arch/i386/reloc.h2
-rw-r--r--arch/x86_64/reloc.h2
-rw-r--r--src/ldso/dynlink.c52
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 <string.h>
#include <elf.h>
+#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 <string.h>
#include <elf.h>
+#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];