X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=b77c6f6b9c8c1dcce7acea8d5bee7128f501ef6d;hb=ce337daa00e42d4f2d9a4d9ae0ed51b20249d924;hp=42b056d2f264aef11978ebf5ebeb8e48523dde69;hpb=b6a6cd703ffefa6352249fb01f4da28d85d17306;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 42b056d2..b77c6f6b 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -423,6 +423,28 @@ static void reclaim_gaps(struct dso *dso) } } +static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t off) +{ + char *q = mmap(p, n, prot, flags, fd, off); + if (q != MAP_FAILED || errno != EINVAL) return q; + /* Fallbacks for MAP_FIXED failure on NOMMU kernels. */ + if (flags & MAP_ANONYMOUS) { + memset(p, 0, n); + return p; + } + ssize_t r; + if (lseek(fd, off, SEEK_SET) < 0) return MAP_FAILED; + for (q=p; n; q+=r, off+=r, n-=r) { + r = read(fd, q, n); + if (r < 0 && errno != EINTR) return MAP_FAILED; + if (!r) { + memset(q, 0, n); + break; + } + } + return p; +} + static void *map_library(int fd, struct dso *dso) { Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)]; @@ -524,19 +546,20 @@ static void *map_library(int fd, struct dso *dso) prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) | ((ph->p_flags&PF_W) ? PROT_WRITE: 0) | ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); - if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) + if (mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) goto error; if (ph->p_memsz > ph->p_filesz) { size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz; size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE; memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1); - if (pgbrk-(size_t)base < this_max && mmap((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + if (pgbrk-(size_t)base < this_max && mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) goto error; } } for (i=0; ((size_t *)(base+dyn))[i]; i+=2) if (((size_t *)(base+dyn))[i]==DT_TEXTREL) { - if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) < 0) + if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) + && errno != ENOSYS) goto error; break; } @@ -927,7 +950,8 @@ static void reloc_all(struct dso *p) do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3); if (head != &ldso && p->relro_start != p->relro_end && - mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) { + mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) + && errno != ENOSYS) { error("Error relocating %s: RELRO protection failed: %m", p->name); if (runtime) longjmp(*rtld_fail, 1); @@ -1192,6 +1216,17 @@ _Noreturn void __dls3(size_t *sp) char **argv_orig = argv; char **envp = argv+argc+1; + /* Find aux vector just past environ[] and use it to initialize + * global data that may be needed before we can make syscalls. */ + __environ = envp; + for (i=argc+1; argv[i]; i++); + libc.auxv = auxv = (void *)(argv+i+1); + decode_vec(auxv, aux, AUX_CNT); + __hwcap = aux[AT_HWCAP]; + libc.page_size = aux[AT_PAGESZ]; + libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] + || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]); + /* Setup early thread pointer in builtin_tls for ldso/libc itself to * use during dynamic linking. If possible it will also serve as the * thread pointer at runtime. */ @@ -1200,25 +1235,11 @@ _Noreturn void __dls3(size_t *sp) a_crash(); } - /* 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); - /* 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] || aux[AT_SECURE]) { - env_path = 0; - env_preload = 0; - libc.secure = 1; + if (!libc.secure) { + env_path = getenv("LD_LIBRARY_PATH"); + env_preload = getenv("LD_PRELOAD"); } - libc.page_size = aux[AT_PAGESZ]; - libc.auxv = auxv; /* If the main program was already loaded by the kernel, * AT_PHDR will point to some location other than the dynamic