From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/14089 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Rodger Combs Newsgroups: gmane.linux.lib.musl.general Subject: [PATCH 3/3] crt: add dcrt1, with support for locating the dynamic loader at runtime Date: Fri, 26 Apr 2019 20:13:29 -0500 Message-ID: <1556327609-27385-3-git-send-email-rodger.combs@gmail.com> References: <1556327609-27385-1-git-send-email-rodger.combs@gmail.com> Reply-To: musl@lists.openwall.com Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="106913"; mail-complaints-to="usenet@blaine.gmane.org" To: musl@lists.openwall.com Original-X-From: musl-return-14105-gllmg-musl=m.gmane.org@lists.openwall.com Sat Apr 27 03:14:03 2019 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by blaine.gmane.org with smtp (Exim 4.89) (envelope-from ) id 1hKBuk-000Rfo-Tx for gllmg-musl@m.gmane.org; Sat, 27 Apr 2019 03:14:03 +0200 Original-Received: (qmail 28422 invoked by uid 550); 27 Apr 2019 01:13:51 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Original-Received: (qmail 28240 invoked from network); 27 Apr 2019 01:13:50 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=qvZNcBL69MpSsQ8/EAEh3PwLUL9f/G9sJZIS1bDj4so=; b=EoIGWiOQE0GXInpxo7QlgC38K+OMxO1u9oLe9dlkKNIHxloBBJAgNdzx77jcd4EE9Q CzIW1mCFfDPvgRxZcKa0R2Gc9kNWvHiwl5Xtl24VbmnP+rIl6F5LXgy806JfxEwCetM1 qadCQ/OdoXozc1KUVtc1rtxs6Jthv+s7cgYHrM+N7swO40qWRxUW1PVQhEvJgkvDk54s 8qbuT70gIXunyTZhZrjowDxBUnwf5E7svuUPwwnT/cVTutHCUkKrABdw8V3djdXQli2O LFBshnBVLwrndsB77WZHWTpJ8BBHhle83lCjiz9dNSUNFXx50fWWeXUii2otRDk961Tj 5L0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=qvZNcBL69MpSsQ8/EAEh3PwLUL9f/G9sJZIS1bDj4so=; b=VwoNoccds8Ln7WYTyudx0WsBpVFHLcNCdoVUwDI4zIk/xV7rKfYP/Pjl0E5tRSUT20 5eJkpwUKpJ4V/Ahv7MOzG1HsAqScXOG8fXzsK0tnEMZpcY6gLbNfrRy8yQjs2RO4xl9Z hC802HAthBtPYh3BsgtIpG5aHHyrIJ6QHiYldxHd5vz86QkCKjRQ+VFGTmXi3HGfA6Nq gBBRuLQJvLtiHMfYKSlpOQ6BSHbfI/+82jT5df1D9HZOS3Ejvg1gMvqL+/JwpBQyqC2I jcQ3tTQZukTElQkFSrzaTy0t/Xn7DUvoDdq+FtlfbHVNwqFSUo9YSAhyCaGU1qMHBxfk /qGw== X-Gm-Message-State: APjAAAVJtEjhDjcUr71ktsI5PQYmBv6nCJq9CENiE1tsLuIVuOwCrbY/ etCi5ICRvb3y9DwKH40VmXj4cR84 X-Google-Smtp-Source: APXvYqyFI2mdxI6n0cD0o+8ISwteH+FZWzZ3Myy1q/phfiHUumnWj59m8GZxzFxaQhjM7bGIIv7psA== X-Received: by 2002:a37:5b86:: with SMTP id p128mr30693141qkb.10.1556327617763; Fri, 26 Apr 2019 18:13:37 -0700 (PDT) X-Mailer: git-send-email 2.7.4 In-Reply-To: <1556327609-27385-1-git-send-email-rodger.combs@gmail.com> Xref: news.gmane.org gmane.linux.lib.musl.general:14089 Archived-At: --- Makefile | 10 +- crt/dcrt1.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++++ ldso/dlstart.c | 57 +++++--- ldso/dynlink.c | 13 ++ ldso/map_library.h | 59 ++++---- src/internal/dynlink.h | 2 +- tools/ld.musl-clang.in | 17 ++- tools/musl-clang.in | 8 ++ tools/musl-gcc.specs.sh | 4 +- 9 files changed, 479 insertions(+), 53 deletions(-) create mode 100644 crt/dcrt1.c diff --git a/Makefile b/Makefile index b46f8ca..163bf03 100644 --- a/Makefile +++ b/Makefile @@ -105,13 +105,15 @@ obj/src/internal/version.h: $(wildcard $(srcdir)/VERSION $(srcdir)/.git) obj/src/internal/version.o obj/src/internal/version.lo: obj/src/internal/version.h -obj/crt/rcrt1.o obj/ldso/dlstart.lo obj/ldso/dynlink.lo: $(srcdir)/src/internal/dynlink.h $(srcdir)/arch/$(ARCH)/reloc.h +obj/crt/rcrt1.o obj/crt/dcrt1.o obj/ldso/dlstart.lo obj/ldso/dynlink.lo: $(srcdir)/src/internal/dynlink.h $(srcdir)/arch/$(ARCH)/reloc.h -obj/crt/crt1.o obj/crt/scrt1.o obj/crt/rcrt1.o obj/ldso/dlstart.lo: $(srcdir)/arch/$(ARCH)/crt_arch.h +obj/crt/crt1.o obj/crt/scrt1.o obj/crt/rcrt1.o obj/crt/dcrt1.o obj/ldso/dlstart.lo: $(srcdir)/arch/$(ARCH)/crt_arch.h -obj/crt/rcrt1.o: $(srcdir)/ldso/dlstart.c +obj/crt/rcrt1.o obj/crt/dcrt1.o: $(srcdir)/ldso/dlstart.c -obj/crt/Scrt1.o obj/crt/rcrt1.o: CFLAGS_ALL += -fPIC +obj/crt/Scrt1.o obj/crt/rcrt1.o obj/crt/dcrt1.o: CFLAGS_ALL += -fPIC + +obj/crt/dcrt1.o: CFLAGS_ALL += -DLDSO_PATHNAME=\"$(LDSO_PATHNAME)\" OPTIMIZE_SRCS = $(wildcard $(OPTIMIZE_GLOBS:%=$(srcdir)/src/%)) $(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.o) $(OPTIMIZE_SRCS:$(srcdir)/%.c=obj/%.lo): CFLAGS += -O3 diff --git a/crt/dcrt1.c b/crt/dcrt1.c new file mode 100644 index 0000000..47c6dc2 --- /dev/null +++ b/crt/dcrt1.c @@ -0,0 +1,362 @@ +#define SYSCALL_NO_TLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include "atomic.h" +#include "dynlink.h" +#include "syscall.h" + +extern weak hidden const size_t _DYNAMIC[]; + +int main(); +weak void _init(); +weak void _fini(); +weak _Noreturn int __libc_start_main(int (*)(), int, char **, + void (*)(), void(*)(), void(*)()); + +#define DLSTART_PROLOGUE __libc_start_main(main, argc, argv, _init, _fini, 0); + +#define START "_start" +#define _dlstart_c _start_c +#include "../ldso/dlstart.c" + +struct dso { + unsigned char *base; + struct fdpic_loadmap *loadmap; + size_t *dynv; + Phdr *phdr; + int phnum; + size_t phentsize; + unsigned char *map; + size_t map_len; +}; + +#ifndef PAGE_SIZE +#define PAGE_SIZE SYSCALL_MMAP2_UNIT +#endif + +#ifdef SYS_mmap2 +#define mmap(start, len, prot, flags, fd, off) (void*)__syscall(SYS_mmap2, start, len, prot, flags, fd, off/SYSCALL_MMAP2_UNIT) +#else +#define mmap(start, len, prot, flags, fd, off) (void*)__syscall(SYS_mmap, start, len, prot, flags, fd, off) +#endif + +#define munmap(ptr, len) __syscall(SYS_munmap, ptr, len) + +static inline int crt_mprotect(void *addr, size_t len, int prot) +{ + size_t start, end; + start = (size_t)addr & -PAGE_SIZE; + end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE; + return __syscall(SYS_mprotect, start, end-start, prot); +} +#define mprotect crt_mprotect + +#define read(fd, buf, size) __syscall(SYS_read, fd, buf, size) +#define pread(fd, buf, size, ofs) __syscall(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs)) + +static inline off_t crt_lseek(int fd, off_t offset, int whence) +{ +#ifdef SYS__llseek + off_t result; + return __syscall(SYS__llseek, fd, offset>>32, offset, &result, whence) ? -1 : result; +#else + return __syscall(SYS_lseek, fd, offset, whence); +#endif +} +#define lseek crt_lseek + +static inline void *map_library_allocz(size_t *size) +{ + void *ret; + *size = (*size + SYSCALL_MMAP2_UNIT - 1) & -SYSCALL_MMAP2_UNIT; + ret = mmap(0, *size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ret == MAP_FAILED) + return NULL; + return ret; +} + +static inline void map_library_free(void *ptr, size_t size) +{ + munmap(ptr, size); +} + +#define map_library_failed(val) ((unsigned long)val > -4096UL) +#define map_library_error(ret) (-(long)ret) + +#ifdef SYS_readlink +#define readlink(path, buf, bufsize) __syscall(SYS_readlink, path, buf, bufsize) +#else +#define readlink(path, buf, bufsize) __syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize) +#endif + +#ifdef SYS_access +#define access(filename, amode) __syscall(SYS_access, filename, amode) +#else +#define access(filename, amode) __syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0) +#endif + +static void *crt_memcpy(void *restrict dest, const void *restrict src, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + for (; n; n--) *d++ = *s++; + return dest; +} + +static void *crt_memset(void *dest, int c, size_t n) +{ + unsigned char *s = dest; + for (; n; n--, s++) *s = c; + return dest; +} +#define memset crt_memset + +static size_t crt_strlen(const char *s) +{ + const char *a = s; + for (; *s; s++); + return s-a; +} + +static char *crt_strchrnul(const char *s, int c) +{ + c = (unsigned char)c; + if (!c) return (char *)s + crt_strlen(s); + for (; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +static int crt_strncmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l=(void *)_l, *r=(void *)_r; + if (!n--) return 0; + for (; *l && *r && n && *l == *r ; l++, r++, n--); + return *l - *r; +} + +static char *crt_getenv(const char *name, char **environ) +{ + size_t l = crt_strchrnul(name, '=') - name; + if (l && !name[l] && environ) + for (char **e = environ; *e; e++) + if (!crt_strncmp(name, *e, l) && l[*e] == '=') + return *e + l+1; + return 0; +} + +#define LD_CRT +#include "../ldso/map_library.h" + +static void decode_vec(size_t *v, size_t *a, size_t cnt) +{ + size_t i; + for (i=0; i 1 && this_path[thisl] == '/') + thisl--; + while (thisl > 0 && this_path[thisl] != '/') + thisl--; + + if (!secure) { + const char *envpath = crt_getenv("LD_LOADER_PATH", environ); + if (envpath) { + size_t envlen = crt_strlen(envpath); + if (envlen < bufsize) { + crt_memcpy(outbuf, envpath, envlen + 1); + return envlen + 1; + } + } + } + + get_rpaths(&paths[0], &paths[2], dyn); + + paths[1] = secure ? NULL : crt_getenv("LD_LIBRARY_PATH", environ); + + for (i = 0; i < 3; i++) { + int relative = 0; + const char *p = paths[i]; + char *o = outbuf; + if (!p) + continue; + for (;;) { + if (!crt_strncmp(p, "$ORIGIN", 7) || + !crt_strncmp(p, "${ORIGIN}", 9)) { + relative = 1; + if (o + thisl + 1 < outbuf + bufsize) { + crt_memcpy(o, this_path, thisl); + o += thisl; + } else { + o = outbuf + bufsize - 1; + } + p += (p[1] == '{' ? 9 : 7); + } else if (*p == ':' || !*p) { +#define LDSO_FILENAME "ld-musl-" LDSO_ARCH ".so.1" + relative |= outbuf[0] != '/'; + if ((!secure || !relative) && o + sizeof(LDSO_FILENAME) + 1 < outbuf + bufsize) { + *o++ = '/'; + crt_memcpy(o, LDSO_FILENAME, sizeof(LDSO_FILENAME)); + if (!access(outbuf, R_OK | X_OK)) + return (o + sizeof(LDSO_FILENAME)) - outbuf; + } + if (!*p) + break; + relative = 0; + o = outbuf; + p++; + } else { + if (o < outbuf + bufsize) + *o++ = *p; + p++; + } + } + } + + // Didn't find a usable loader anywhere, so try the hardcoded path :shrug: + crt_memcpy(outbuf, LDSO_PATHNAME, sizeof(LDSO_PATHNAME)); + return sizeof(LDSO_PATHNAME); +} + +static void final_start_c(long *p) +{ + int argc = p[0]; + char **argv = (void *)(p+1); + __libc_start_main(main, argc, argv, _init, _fini, 0); +} + +hidden _Noreturn void __dls2(unsigned char *base, size_t *p, size_t *dyn) +{ + int argc = p[0]; + char **argv = (void *)(p+1); + int fd; + int secure; + int prot = PROT_READ; + struct dso loader; + Ehdr *loader_hdr; + Phdr *new_hdr; + void *entry; + char this_path[2*NAME_MAX+2] = {0}; + size_t thisl; + char linker_path[2*NAME_MAX+2] = {0}; + size_t linker_len; + size_t i; + size_t aux[AUX_CNT]; + size_t *auxv; + char **environ = 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. */ + for (i = argc + 1; argv[i]; i++); + auxv = (void *)(argv + i + 1); + decode_vec(auxv, aux, AUX_CNT); + secure = ((aux[0] & 0x7800) != 0x7800 || aux[AT_UID] != aux[AT_EUID] + || aux[AT_GID] != aux[AT_EGID] || aux[AT_SECURE]); + + thisl = readlink("/proc/self/exe", this_path, sizeof this_path); + linker_len = find_linker(linker_path, sizeof linker_path, this_path, thisl, dyn, environ, secure); + + fd = __sys_open2(, linker_path, O_RDONLY); + if (fd < 0) + goto error; + + loader_hdr = map_library(fd, &loader); + if (!loader_hdr) + goto error; + + __syscall(SYS_close, fd); + + // Copy the program headers into an anonymous mapping + new_hdr = mmap(0, (aux[AT_PHENT] * (aux[AT_PHNUM] + 2) + linker_len + PAGE_SIZE - 1) & -PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_library_failed(new_hdr)) + goto error; + + // Point it back at the original kernel-provided base + new_hdr->p_type = PT_PHDR; + new_hdr->p_vaddr = (size_t)new_hdr - (size_t)base; + + ((Phdr*)((char*)new_hdr + aux[AT_PHENT]))->p_type = PT_INTERP; + ((Phdr*)((char*)new_hdr + aux[AT_PHENT]))->p_vaddr = new_hdr->p_vaddr + aux[AT_PHENT] * (aux[AT_PHNUM] + 2); + + crt_memcpy((char*)new_hdr + aux[AT_PHENT] * (aux[AT_PHNUM] + 2), linker_path, linker_len); + + for (i = 0; i < aux[AT_PHNUM]; i++) { + Phdr *hdr = (void*)((char*)aux[AT_PHDR] + aux[AT_PHENT] * i); + Phdr *dst = (void*)((char*)new_hdr + aux[AT_PHENT] * (i + 2)); + if (hdr->p_type == PT_PHDR || hdr->p_type == PT_INTERP) { + // Can't have a duplicate + dst->p_type = PT_NULL; + } else { + crt_memcpy(dst, hdr, aux[AT_PHENT]); + } + } + + if (mprotect(new_hdr, aux[AT_PHENT] * (aux[AT_PHNUM] + 2) + linker_len, PROT_READ)) + goto error; + + for (i=0; auxv[i]; i+=2) { + if (auxv[i] == AT_BASE) + auxv[i + 1] = (size_t)loader_hdr; + if (auxv[i] == AT_PHDR) + auxv[i + 1] = (size_t)new_hdr; + if (auxv[i] == AT_PHNUM) + auxv[i + 1] += 2; + } + + entry = laddr(&loader, loader_hdr->e_entry); + +#ifndef LD_FDPIC + /* Undo the relocations performed by dlstart */ + + if (NEED_MIPS_GOT_RELOCS) { + const size_t *dynv = _DYNAMIC; + size_t local_cnt = 0; + size_t *got = (void *)(base + dyn[DT_PLTGOT]); + for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO) + local_cnt = dynv[i+1]; + for (i=0; i