X-Git-Url: http://nsz.repo.hu/git/?p=musl;a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=3fafb181a728528afeda74711571714053828878;hp=226e174f6de6af2d24d0529ca2a698f8a61ac33b;hb=623753ad64a3625b010c10c00c45262d2eec2495;hpb=a53de812d258a7b0be44ce5dfc96e0f8ce137817 diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 226e174f..3fafb181 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "reloc.h" @@ -92,10 +93,12 @@ static Sym *lookup(const char *s, uint32_t h, Sym *syms, uint32_t *hashtab, char } #define OK_TYPES (1<next) { @@ -103,10 +106,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 +305,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; } @@ -404,6 +411,20 @@ static void load_deps(struct dso *p) } } +static void load_preload(char *s) +{ + int tmp; + char *z; + for (z=s; *z; s=z) { + for ( ; *s && isspace(*s); s++); + for (z=s; *z && !isspace(*z); z++); + tmp = *z; + *z = 0; + load_library(s); + *z = tmp; + } +} + static void make_global(struct dso *p) { for (; p; p=p->next) p->global = 1; @@ -440,25 +461,39 @@ 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; - static struct dso builtin_dsos[2]; + 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; + char *env_preload=0; /* Find aux vector just past environ[] */ for (i=argc+1; argv[i]; i++) if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16)) env_path = argv[i]+16; + else if (!memcmp(argv[i], "LD_PRELOAD=", 11)) + env_preload = argv[i]+11; auxv = (void *)(argv+i+1); 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]) { env_path = 0; + env_preload = 0; } /* Relocate ldso's DYNAMIC pointer and load vector */ @@ -495,6 +530,26 @@ 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); @@ -511,6 +566,7 @@ void *__dynlink(int argc, char **argv, size_t *got) head = tail = app; libc = lib; app->next = 0; + if (env_preload) load_preload(env_preload); load_deps(head); make_global(head); @@ -582,11 +638,16 @@ end: return p; } -static void *do_dlsym(struct dso *p, const char *s) +static void *do_dlsym(struct dso *p, const char *s, void *ra) { size_t i; uint32_t h; Sym *sym; + if (p == RTLD_NEXT) { + for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next); + if (!p) p=head; + p=p->next; + } if (p == head || p == RTLD_DEFAULT) return find_sym(head, s, 0); h = hash(s); @@ -602,11 +663,11 @@ static void *do_dlsym(struct dso *p, const char *s) return 0; } -void *dlsym(void *p, const char *s) +void *__dlsym(void *p, const char *s, void *ra) { void *res; pthread_rwlock_rdlock(&lock); - res = do_dlsym(p, s); + res = do_dlsym(p, s, ra); pthread_rwlock_unlock(&lock); return res; }