make dynamic linker accept : or \n as path separator
[musl] / src / ldso / dynlink.c
index 782e979..dec9511 100644 (file)
@@ -99,6 +99,7 @@ static int ssp_used;
 static int runtime;
 static int ldd_mode;
 static int ldso_fail;
+static int noload;
 static jmp_buf rtld_fail;
 static pthread_rwlock_t lock;
 static struct debug debug;
@@ -402,16 +403,16 @@ error:
        return 0;
 }
 
-static int path_open(const char *name, const char *search, char *buf, size_t buf_size)
+static int path_open(const char *name, const char *s, char *buf, size_t buf_size)
 {
-       const char *s=search, *z;
-       int l, fd;
+       size_t l;
+       int fd;
        for (;;) {
-               while (*s==':') s++;
-               if (!*s) return -1;
-               z = strchr(s, ':');
-               l = z ? z-s : strlen(s);
-               snprintf(buf, buf_size, "%.*s/%s", l, s, name);
+               s += strspn(s, ":\n");
+               l = strcspn(s, ":\n");
+               if (l-1 >= INT_MAX) return -1;
+               if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) >= buf_size)
+                       continue;
                if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd;
                s += l;
        }
@@ -434,7 +435,6 @@ static struct dso *load_library(const char *name)
        char buf[2*NAME_MAX+2];
        const char *pathname;
        unsigned char *map;
-       size_t map_len;
        struct dso *p, temp_dso = {0};
        int fd;
        struct stat st;
@@ -508,7 +508,7 @@ static struct dso *load_library(const char *name)
                        return p;
                }
        }
-       map = map_library(fd, &temp_dso);
+       map = noload ? 0 : map_library(fd, &temp_dso);
        close(fd);
        if (!map) return 0;
 
@@ -527,7 +527,7 @@ static struct dso *load_library(const char *name)
        }
        p = calloc(1, alloc_size);
        if (!p) {
-               munmap(map, map_len);
+               munmap(map, temp_dso.map_len);
                return 0;
        }
        memcpy(p, &temp_dso, sizeof temp_dso);
@@ -541,8 +541,8 @@ static struct dso *load_library(const char *name)
        if (pathname != name) p->shortname = strrchr(p->name, '/')+1;
        if (p->tls_image) {
                if (runtime && !__pthread_self_init()) {
+                       munmap(map, p->map_len);
                        free(p);
-                       munmap(map, map_len);
                        return 0;
                }
                p->tls_id = ++tls_cnt;
@@ -1027,6 +1027,7 @@ void *dlopen(const char *file, int mode)
        orig_tls_offset = tls_offset;
        orig_tls_align = tls_align;
        orig_tail = tail;
+       noload = mode & RTLD_NOLOAD;
 
        if (setjmp(rtld_fail)) {
                /* Clean up anything new that was (partially) loaded */
@@ -1050,8 +1051,10 @@ void *dlopen(const char *file, int mode)
        } else p = load_library(file);
 
        if (!p) {
-               snprintf(errbuf, sizeof errbuf,
-                       "Error loading shared library %s: %m", file);
+               snprintf(errbuf, sizeof errbuf, noload ?
+                       "Library %s is not already loaded" :
+                       "Error loading shared library %s: %m",
+                       file);
                errflag = 1;
                goto end;
        }
@@ -1091,7 +1094,7 @@ end:
        return p;
 }
 
-static int invalid_dso_handle(struct dso *h)
+static int invalid_dso_handle(void *h)
 {
        struct dso *p;
        for (p=head; p; p=p->next) if (h==p) return 0;
@@ -1119,7 +1122,8 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
                        return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value});
                return def.dso->base + def.sym->st_value;
        }
-       if (invalid_dso_handle(p)) return 0;
+       if (p != RTLD_DEFAULT && p != RTLD_NEXT && invalid_dso_handle(p))
+               return 0;
        if (p->ghashtab) {
                gh = gnu_hash(s);
                sym = gnu_lookup(s, gh, p);
@@ -1188,7 +1192,7 @@ int __dladdr(void *addr, Dl_info *info)
        }
 
        for (; nsym; nsym--, sym++) {
-               if (sym->st_shndx && sym->st_value
+               if (sym->st_value
                 && (1<<(sym->st_info&0xf) & OK_TYPES)
                 && (1<<(sym->st_info>>4) & OK_BINDS)) {
                        void *symaddr = p->base + sym->st_value;
@@ -1246,7 +1250,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void
        return ret;
 }
 #else
-static int invalid_dso_handle(struct dso *h)
+static int invalid_dso_handle(void *h)
 {
        snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
        errflag = 1;