timedwait: play it safe for now
[musl] / src / ldso / dynlink.c
index 33937e7..7a26e9e 100644 (file)
@@ -92,10 +92,12 @@ static Sym *lookup(const char *s, uint32_t h, Sym *syms, uint32_t *hashtab, char
 }
 
 #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
+#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
 
 static void *find_sym(struct dso *dso, const char *s, int need_def)
 {
        uint32_t h = hash(s);
+       void *def = 0;
        if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
        if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
        for (; dso; dso=dso->next) {
@@ -103,10 +105,14 @@ static void *find_sym(struct dso *dso, const char *s, int need_def)
                if (!dso->global) continue;
                sym = lookup(s, h, dso->syms, dso->hashtab, dso->strings);
                if (sym && (!need_def || sym->st_shndx) && sym->st_value
-                && (1<<(sym->st_info&0xf) & OK_TYPES))
-                       return dso->base + sym->st_value;
+                && (1<<(sym->st_info&0xf) & OK_TYPES)
+                && (1<<(sym->st_info>>4) & OK_BINDS)) {
+                       if (def && sym->st_info>>4 == STB_WEAK) continue;
+                       def = dso->base + sym->st_value;
+                       if (sym->st_info>>4 == STB_GLOBAL) break;
+               }
        }
-       return 0;
+       return def;
 }
 
 static void do_relocs(unsigned char *base, size_t *rel, size_t rel_size, size_t stride, Sym *syms, char *strings, struct dso *dso)
@@ -298,7 +304,7 @@ static struct dso *load_library(const char *name)
                                if (!libc->prev) {
                                        tail->next = libc;
                                        libc->prev = tail;
-                                       tail = libc;
+                                       tail = libc->next ? libc->next : libc;
                                }
                                return libc;
                        }
@@ -440,10 +446,15 @@ void *__dynlink(int argc, char **argv, size_t *got)
        size_t *auxv, aux[AUX_CNT] = {0};
        size_t app_dyn[DYN_CNT] = {0};
        size_t lib_dyn[DYN_CNT] = {0};
+       size_t vdso_dyn[DYN_CNT] = {0};
        size_t i;
        Phdr *phdr;
        Ehdr *ehdr;
-       struct dso lib, app;
+       static struct dso builtin_dsos[3];
+       struct dso *const app = builtin_dsos+0;
+       struct dso *const lib = builtin_dsos+1;
+       struct dso *const vdso = builtin_dsos+2;
+       size_t vdso_base=0;
 
        /* Find aux vector just past environ[] */
        for (i=argc+1; argv[i]; i++)
@@ -453,6 +464,13 @@ void *__dynlink(int argc, char **argv, size_t *got)
 
        decode_vec(auxv, aux, AUX_CNT);
 
+       for (i=0; auxv[i]; i+=2) {
+               if (auxv[i]==AT_SYSINFO_EHDR) {
+                       vdso_base = auxv[i+1];
+                       break;
+               }
+       }
+
        /* 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]) {
@@ -471,7 +489,7 @@ void *__dynlink(int argc, char **argv, size_t *got)
                }
        }
 
-       app = (struct dso){
+       *app = (struct dso){
                .base = 0,
                .strings = (void *)(app_dyn[DT_STRTAB]),
                .hashtab = (void *)(app_dyn[DT_HASH]),
@@ -479,10 +497,10 @@ void *__dynlink(int argc, char **argv, size_t *got)
                .dynv = (void *)(phdr->p_vaddr),
                .name = argv[0],
                .global = 1,
-               .next = &lib
+               .next = lib
        };
 
-       lib = (struct dso){
+       *lib = (struct dso){
                .base = (void *)aux[AT_BASE],
                .strings = (void *)(aux[AT_BASE]+lib_dyn[DT_STRTAB]),
                .hashtab = (void *)(aux[AT_BASE]+lib_dyn[DT_HASH]),
@@ -493,41 +511,53 @@ void *__dynlink(int argc, char **argv, size_t *got)
                .relocated = 1
        };
 
+       if (vdso_base) {
+               ehdr = (void *)vdso_base;
+               phdr = (void *)(vdso_base + ehdr->e_phoff);
+               for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
+                       if (phdr->p_type == PT_DYNAMIC)
+                               vdso->dynv = (void *)(vdso_base + phdr->p_offset);
+                       if (phdr->p_type == PT_LOAD)
+                               vdso->base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset);
+               }
+               decode_vec(vdso->dynv, vdso_dyn, DYN_CNT);
+               vdso->syms = (void *)(vdso->base + vdso_dyn[DT_SYMTAB]);
+               vdso->hashtab = (void *)(vdso->base + vdso_dyn[DT_HASH]);
+               vdso->strings = (void *)(vdso->base + vdso_dyn[DT_STRTAB]);
+               vdso->name = "linux-gate.so.1";
+               vdso->global = 1;
+
+               vdso->prev = lib;
+               lib->next = vdso;
+       }
+
        /* Relocate the dynamic linker/libc */
        do_relocs((void *)aux[AT_BASE], (void *)(aux[AT_BASE]+lib_dyn[DT_REL]),
-               lib_dyn[DT_RELSZ], 2, lib.syms, lib.strings, &app);
+               lib_dyn[DT_RELSZ], 2, lib->syms, lib->strings, app);
        do_relocs((void *)aux[AT_BASE], (void *)(aux[AT_BASE]+lib_dyn[DT_RELA]),
-               lib_dyn[DT_RELASZ], 3, lib.syms, lib.strings, &app);
+               lib_dyn[DT_RELASZ], 3, lib->syms, lib->strings, app);
 
        /* At this point the standard library is fully functional */
 
-       reclaim_gaps(app.base, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
-       ehdr = (void *)lib.base;
-       reclaim_gaps(lib.base, (void *)(lib.base+ehdr->e_phoff),
+       reclaim_gaps(app->base, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
+       ehdr = (void *)lib->base;
+       reclaim_gaps(lib->base, (void *)(lib->base+ehdr->e_phoff),
                ehdr->e_phentsize, ehdr->e_phnum);
 
-       head = tail = &app;
-       libc = &lib;
-       app.next = 0;
+       head = tail = app;
+       libc = lib;
+       app->next = 0;
        load_deps(head);
 
        make_global(head);
        reloc_all(head->next);
        reloc_all(head);
 
-       if (rtld_used) {
-               runtime = 1;
-               head->next->prev = malloc(sizeof *head);
-               *head->next->prev = *head;
-               head = head->next->prev;
-               libc->prev->next = malloc(sizeof *libc);
-               *libc->prev->next = *libc;
-               libc = libc->prev->next;
-               if (libc->next) libc->next->prev = libc;
-               if (tail == &lib) tail = libc;
-       } else {
+       runtime = 1;
+       if (!rtld_used) {
                free_all(head);
                free(sys_path);
+               reclaim((void *)builtin_dsos, 0, sizeof builtin_dsos);
        }
 
        errno = 0;