diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2016-05-07 19:05:25 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2016-05-07 19:05:25 +0000 |
commit | be4e94637d7117375492627b79c41629c7da9bc3 (patch) | |
tree | 61a9fabcc07d38d2720bbb937e83103928286550 /libexec/ld.so | |
parent | 33d8693716b4a6d503e0ba97f94a783905b87f28 (diff) |
Use a Thread Information Block in both single and multi-threaded programs.
This stores errno, the cancelation flags, and related bits for each thread
and is allocated by ld.so or libc.a. This is an ABI break from 5.9-stable!
Make libpthread dlopen'able by moving the cancelation wrappers into libc
and doing locking and fork/errno handling via callbacks that libpthread
registers when it first initializes. 'errno' *must* be declared via
<errno.h> now!
Clean up libpthread's symbol exports like libc.
On powerpc, offset the TIB/TCB/TLS data from the register per the ELF spec.
Testing by various, particularly sthen@ and patrick@
ok kettenis@
Diffstat (limited to 'libexec/ld.so')
29 files changed, 343 insertions, 31 deletions
diff --git a/libexec/ld.so/Makefile b/libexec/ld.so/Makefile index 50be47137fd..5c6da586143 100644 --- a/libexec/ld.so/Makefile +++ b/libexec/ld.so/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.60 2015/08/31 02:53:57 guenther Exp $ +# $OpenBSD: Makefile,v 1.61 2016/05/07 19:05:23 guenther Exp $ SUBDIR=ldconfig ldd MAN= ld.so.1 @@ -19,7 +19,7 @@ VPATH=${.CURDIR}/../../lib/libc/string SRCS= ldasm.S boot.c loader.c resolve.c dlfcn.c dl_printf.c rtld_machine.c SRCS+= path.c util.c sod.c strsep.c strtol.c dir.c library_subr.c dl_prebind.c SRCS+= dl_realpath.c dl_uname.c dl_dirname.c strlcat.c strlen.c trace.c -SRCS+= malloc.c reallocarray.c +SRCS+= malloc.c reallocarray.c tib.c .if (${MACHINE_ARCH} == "i386") SRCS+= library_mquery.c diff --git a/libexec/ld.so/Symbols.map b/libexec/ld.so/Symbols.map index e167f603dfe..795caac6108 100644 --- a/libexec/ld.so/Symbols.map +++ b/libexec/ld.so/Symbols.map @@ -14,6 +14,10 @@ /* alias in reserved namespace for libpthread to use */ _dlctl; + /* TLS related bits */ + _dl_allocate_tib; + _dl_free_tib; + /* looked up by gdb */ _dl_bind; _dl_debug_state; diff --git a/libexec/ld.so/alpha/ldasm.S b/libexec/ld.so/alpha/ldasm.S index f71de97c74d..952b0c7e174 100644 --- a/libexec/ld.so/alpha/ldasm.S +++ b/libexec/ld.so/alpha/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.34 2016/03/21 22:41:28 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.35 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -317,6 +317,7 @@ DL_SYSCALL(sendsyslog) DL_SYSCALL(pledge) DL_SYSCALL(gettimeofday) DL_SYSCALL_NOERR(issetugid) +DL_SYSCALL_NOERR(getthrid) DL_SYSCALL(lstat) DL_SYSCALL(mprotect) DL_SYSCALL(munmap) @@ -324,6 +325,7 @@ DL_SYSCALL(open) DL_SYSCALL(read) DL_SYSCALL(readlink) DL_SYSCALL2(_syscall,__syscall) +DL_SYSCALL2_NOERR(set_tcb,__set_tcb) DL_SYSCALL(sysctl) DL_SYSCALL(utrace) DL_SYSCALL(write) diff --git a/libexec/ld.so/alpha/syscall.h b/libexec/ld.so/alpha/syscall.h index df364c4715e..8005b3e3307 100644 --- a/libexec/ld.so/alpha/syscall.h +++ b/libexec/ld.so/alpha/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.32 2016/03/21 22:41:28 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.33 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -41,6 +41,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); void * _dl_mmap(void *, size_t, int, int, int, off_t); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/amd64/ldasm.S b/libexec/ld.so/amd64/ldasm.S index 2dc0fe096ed..922c1b8aea2 100644 --- a/libexec/ld.so/amd64/ldasm.S +++ b/libexec/ld.so/amd64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.23 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.24 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2002,2004 Dale Rahn @@ -87,6 +87,7 @@ DL_SYSCALL(read) DL_SYSCALL(write) DL_SYSCALL(close) DL_SYSCALL(issetugid) +DL_SYSCALL(getthrid) DL_SYSCALL(getdents) DL_SYSCALL(mprotect) DL_SYSCALL(munmap) diff --git a/libexec/ld.so/amd64/syscall.h b/libexec/ld.so/amd64/syscall.h index 26ebf6c4092..270e9bb2468 100644 --- a/libexec/ld.so/amd64/syscall.h +++ b/libexec/ld.so/amd64/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.20 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.21 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/arm/ldasm.S b/libexec/ld.so/arm/ldasm.S index 36f1ab62bc2..80365b9b9c8 100644 --- a/libexec/ld.so/arm/ldasm.S +++ b/libexec/ld.so/arm/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.21 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.22 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2004 Dale Rahn @@ -113,6 +113,7 @@ _dl_exit: b 1b DL_SYSCALL(issetugid) +DL_SYSCALL(getthrid) DL_SYSCALL2(_syscall,__syscall) DL_SYSCALL(munmap) DL_SYSCALL(mprotect) @@ -129,6 +130,7 @@ DL_SYSCALL(sendsyslog) DL_SYSCALL(pledge) DL_SYSCALL2(getcwd,__getcwd) DL_SYSCALL(sysctl) +DL_SYSCALL2(set_tcb,__set_tcb) DL_SYSCALL(getdents) diff --git a/libexec/ld.so/arm/syscall.h b/libexec/ld.so/arm/syscall.h index d9ecc3b2c3a..d74a9e26c3d 100644 --- a/libexec/ld.so/arm/syscall.h +++ b/libexec/ld.so/arm/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.20 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.21 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/hppa/ldasm.S b/libexec/ld.so/hppa/ldasm.S index 59e5902e676..1663eb65f04 100644 --- a/libexec/ld.so/hppa/ldasm.S +++ b/libexec/ld.so/hppa/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.20 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.21 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2004 Michael Shalayeff @@ -182,6 +182,12 @@ ENTRY(_dl_issetugid,0) nop EXIT(_dl_issetugid) +ENTRY(_dl_getthrid,0) + SYSCALL(getthrid) + bv r0(rp) + nop +EXIT(_dl_getthrid) + ENTRY(_dl__syscall,0) SYSCALL(__syscall) bv r0(rp) @@ -278,6 +284,12 @@ ENTRY(_dl_sendsyslog,0) nop EXIT(_dl_sendsyslog) +ENTRY(_dl_set_tcb,0) + SYSCALL(__set_tcb) + bv r0(rp) + nop +EXIT(_dl_set_tcb) + ENTRY(_dl_pledge,0) SYSCALL(pledge) bv r0(rp) diff --git a/libexec/ld.so/hppa/syscall.h b/libexec/ld.so/hppa/syscall.h index 26ebf6c4092..270e9bb2468 100644 --- a/libexec/ld.so/hppa/syscall.h +++ b/libexec/ld.so/hppa/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.20 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.21 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/i386/ldasm.S b/libexec/ld.so/i386/ldasm.S index 86c5f0d7376..621a1c503be 100644 --- a/libexec/ld.so/i386/ldasm.S +++ b/libexec/ld.so/i386/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.25 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.26 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2002 Dale Rahn @@ -109,6 +109,7 @@ _dl_exit: DL_SYSCALL(issetugid) +DL_SYSCALL(getthrid) DL_SYSCALL2(_syscall,__syscall) DL_SYSCALL(munmap) DL_SYSCALL(mprotect) @@ -126,6 +127,7 @@ DL_SYSCALL(pledge) DL_SYSCALL2(getcwd,__getcwd) DL_SYSCALL(sysctl) DL_SYSCALL(getdents) +DL_SYSCALL2(set_tcb,__set_tcb) .L_cerr: /* error: result = -errno; - handled here. */ diff --git a/libexec/ld.so/i386/syscall.h b/libexec/ld.so/i386/syscall.h index 811c8acbdae..9b8a4bc352a 100644 --- a/libexec/ld.so/i386/syscall.h +++ b/libexec/ld.so/i386/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.24 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.25 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c index 9a945b37b37..5318af38592 100644 --- a/libexec/ld.so/library.c +++ b/libexec/ld.so/library.c @@ -1,4 +1,4 @@ -/* $OpenBSD: library.c,v 1.74 2016/03/20 02:29:51 guenther Exp $ */ +/* $OpenBSD: library.c,v 1.75 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2002 Dale Rahn @@ -104,6 +104,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags) Elf_Dyn *dynp = NULL; Elf_Ehdr *ehdr; Elf_Phdr *phdp; + Elf_Phdr *ptls = NULL; struct stat sb; void *prebind_data; @@ -164,6 +165,17 @@ _dl_tryload_shlib(const char *libname, int type, int flags) dynp = (Elf_Dyn *)phdp->p_vaddr; break; case PT_TLS: + if (phdp->p_filesz > phdp->p_memsz) { + _dl_printf("%s: invalid tls data in %s.\n", + __progname, libname); + _dl_close(libfile); + _dl_errno = DL_CANT_LOAD_OBJ; + return(0); + } + if (!_dl_tib_static_done) { + ptls = phdp; + break; + } _dl_printf("%s: unsupported TLS program header in %s\n", __progname, libname); _dl_close(libfile); @@ -283,6 +295,8 @@ _dl_tryload_shlib(const char *libname, int type, int flags) object->inode = sb.st_ino; object->obj_flags |= flags; _dl_set_sod(object->load_name, &object->sod); + if (ptls != NULL && ptls->p_memsz) + _dl_set_tls(object, ptls, libaddr, libname); } else { _dl_munmap((void *)libaddr, maxva - minva); _dl_load_list_free(load_list); diff --git a/libexec/ld.so/library_mquery.c b/libexec/ld.so/library_mquery.c index 48151f6d4fa..870f54d7065 100644 --- a/libexec/ld.so/library_mquery.c +++ b/libexec/ld.so/library_mquery.c @@ -1,4 +1,4 @@ -/* $OpenBSD: library_mquery.c,v 1.52 2016/03/20 02:29:51 guenther Exp $ */ +/* $OpenBSD: library_mquery.c,v 1.53 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2002 Dale Rahn @@ -108,6 +108,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags) Elf_Phdr *phdp; Elf_Addr load_end = 0; Elf_Addr align = _dl_pagesz - 1, off, size; + Elf_Phdr *ptls = NULL; struct stat sb; void *prebind_data; char hbuf[4096]; @@ -205,6 +206,17 @@ _dl_tryload_shlib(const char *libname, int type, int flags) dynp = (Elf_Dyn *)phdp->p_vaddr; break; case PT_TLS: + if (phdp->p_filesz > phdp->p_memsz) { + _dl_printf("%s: invalid tls data in %s.\n", + __progname, libname); + _dl_close(libfile); + _dl_errno = DL_CANT_LOAD_OBJ; + return(0); + } + if (!_dl_tib_static_done) { + ptls = phdp; + break; + } _dl_printf("%s: unsupported TLS program header in %s\n", __progname, libname); _dl_close(libfile); @@ -309,6 +321,9 @@ retry: object->inode = sb.st_ino; object->obj_flags |= flags; _dl_set_sod(object->load_name, &object->sod); + if (ptls != NULL && ptls->p_memsz) + _dl_set_tls(object, ptls, (Elf_Addr)lowld->start, + libname); } else { _dl_load_list_free(lowld); } diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index e5e4ebebaab..609103d4c53 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.158 2016/03/24 05:27:19 guenther Exp $ */ +/* $OpenBSD: loader.c,v 1.159 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -391,6 +391,7 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) int failed; struct dep_node *n; Elf_Addr minva, maxva, exe_loff; + Elf_Phdr *ptls = NULL; int align; _dl_setup_env(argv[0], envp); @@ -480,9 +481,12 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) } break; case PT_TLS: - _dl_printf("%s: unsupported TLS program header\n", - __progname); - _dl_exit(1); + if (phdp->p_filesz > phdp->p_memsz) { + _dl_printf("%s: invalid tls data.\n", + __progname); + _dl_exit(5); + } + ptls = phdp; break; } phdp++; @@ -492,6 +496,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) exe_obj->load_size = maxva - minva; _dl_set_sod(exe_obj->load_name, &exe_obj->sod); + /* TLS bits in the base executable */ + if (ptls != NULL && ptls->p_memsz) + _dl_set_tls(exe_obj, ptls, exe_loff, NULL); + n = _dl_malloc(sizeof *n); if (n == NULL) _dl_exit(5); @@ -522,6 +530,9 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) dyn_obj->status |= STAT_RELOC_DONE; _dl_set_sod(dyn_obj->load_name, &dyn_obj->sod); + /* calculate the offsets for static TLS allocations */ + _dl_allocate_tls_offsets(); + /* * Everything should be in place now for doing the relocation * and binding. Call _dl_rtld to do the job. Fingers crossed. @@ -551,6 +562,9 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) _dl_loading_object = NULL; + /* set up the TIB for the initial thread */ + _dl_allocate_first_tib(); + _dl_fixup_user_env(); /* diff --git a/libexec/ld.so/m88k/ldasm.S b/libexec/ld.so/m88k/ldasm.S index c5ce9333855..ca2c33a854d 100644 --- a/libexec/ld.so/m88k/ldasm.S +++ b/libexec/ld.so/m88k/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.18 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.19 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2013 Miodrag Vallat. @@ -173,6 +173,9 @@ ENTRY(_dl_exit) DL_SYSCALL(issetugid) jmp %r1 +DL_SYSCALL(getthrid) + jmp %r1 + DL_SYSCALL2(_syscall,__syscall) jmp %r1 diff --git a/libexec/ld.so/m88k/syscall.h b/libexec/ld.so/m88k/syscall.h index f67e610c9d2..d1de184c957 100644 --- a/libexec/ld.so/m88k/syscall.h +++ b/libexec/ld.so/m88k/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.16 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.17 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); diff --git a/libexec/ld.so/mips64/ldasm.S b/libexec/ld.so/mips64/ldasm.S index ec2e63e06af..a3172abfb03 100644 --- a/libexec/ld.so/mips64/ldasm.S +++ b/libexec/ld.so/mips64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.18 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.19 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1998-2002 Opsycon AB, Sweden. @@ -28,6 +28,7 @@ #include <machine/asm.h> #include <sys/syscall.h> +#define __cerror _dl_cerror #include <SYS.h> /* Stack at this stage is: @@ -155,6 +156,7 @@ DL_SYSCALL(sendsyslog) DL_SYSCALL(pledge) DL_SYSCALL(gettimeofday) DL_SYSCALL_NOERR(issetugid) +DL_SYSCALL_NOERR(getthrid) DL_SYSCALL(lstat) DL_SYSCALL(mprotect) DL_SYSCALL(munmap) @@ -162,6 +164,7 @@ DL_SYSCALL(open) DL_SYSCALL(read) DL_SYSCALL(readlink) DL_SYSCALL2(_syscall,__syscall) +DL_SYSCALL2_NOERR(set_tcb,__set_tcb) DL_SYSCALL(sysctl) DL_SYSCALL(utrace) DL_SYSCALL(write) diff --git a/libexec/ld.so/mips64/syscall.h b/libexec/ld.so/mips64/syscall.h index 30fe1458a98..8b85bed5124 100644 --- a/libexec/ld.so/mips64/syscall.h +++ b/libexec/ld.so/mips64/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.22 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.23 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1998-2002 Opsycon AB, Sweden. @@ -45,12 +45,14 @@ int _dl_getcwd(char *, size_t); ssize_t _dl_getdents(int, char *, size_t); int _dl_gettimeofday(struct timeval *, struct timezone *); int _dl_issetugid(void); +int _dl_getthrid(void); int _dl_lstat(const char *, struct stat *); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); int _dl_open(const char *, int); ssize_t _dl_read(int, const char *, size_t); ssize_t _dl_readlink(const char *, char *, size_t); +void _dl_set_tcb(void *); int _dl_pledge(const char *, const char **); long _dl__syscall(quad_t, ...); int _dl_sysctl(const int *, u_int, void *, size_t *, void *, size_t); diff --git a/libexec/ld.so/powerpc/ldasm.S b/libexec/ld.so/powerpc/ldasm.S index 0b2c9753d58..1ad7d009259 100644 --- a/libexec/ld.so/powerpc/ldasm.S +++ b/libexec/ld.so/powerpc/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.28 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.29 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1999 Dale Rahn @@ -151,6 +151,7 @@ DL_SYSCALL(sendsyslog) DL_SYSCALL(pledge) DL_SYSCALL(gettimeofday) DL_SYSCALL_NOERR(issetugid) +DL_SYSCALL_NOERR(getthrid) DL_SYSCALL(lstat) DL_SYSCALL(mmap) DL_SYSCALL(mprotect) diff --git a/libexec/ld.so/powerpc/syscall.h b/libexec/ld.so/powerpc/syscall.h index 24da619b6eb..42dbcfd57c2 100644 --- a/libexec/ld.so/powerpc/syscall.h +++ b/libexec/ld.so/powerpc/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.40 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.41 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -45,6 +45,7 @@ int _dl_getcwd(char *, size_t); ssize_t _dl_getdents(int, char *, size_t); int _dl_gettimeofday(struct timeval *, struct timezone *); int _dl_issetugid(void); +int _dl_getthrid(void); int _dl_lstat(const char *, struct stat *); void * _dl_mmap(void *, size_t, int, int, int, off_t); int _dl_mprotect(const void *, size_t, int); diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index 8a1b2845dfb..7881b4a89a5 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.h,v 1.76 2016/03/20 02:29:51 guenther Exp $ */ +/* $OpenBSD: resolve.h,v 1.77 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -143,6 +143,13 @@ struct elf_object { dev_t dev; ino_t inode; + /* thread local storage info */ + Elf_Addr tls_fsize; + Elf_Addr tls_msize; + Elf_Addr tls_align; + const void *tls_static_data; + int tls_offset; + /* generation number of last grpsym insert on this object */ unsigned int grpsym_gen; @@ -245,6 +252,13 @@ void _dl_trace_setup(char **); void _dl_trace_object_setup(elf_object_t *); int _dl_trace_plt(const elf_object_t *, const char *); +/* tib.c */ +void _dl_allocate_tls_offsets(void); +void _dl_allocate_first_tib(void); +void _dl_set_tls(elf_object_t *_object, Elf_Phdr *_ptls, Elf_Addr _libaddr, + const char *_libname); +extern int _dl_tib_static_done; + extern elf_object_t *_dl_objects; extern elf_object_t *_dl_last_object; diff --git a/libexec/ld.so/sh/ldasm.S b/libexec/ld.so/sh/ldasm.S index cafd90ea8f8..095533c726f 100644 --- a/libexec/ld.so/sh/ldasm.S +++ b/libexec/ld.so/sh/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.23 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.24 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2006 Dale Rahn @@ -172,6 +172,7 @@ _dl_exit: nop DL_SYSCALL(issetugid) +DL_SYSCALL(getthrid) DL_SYSCALL2(_syscall,__syscall) DL_SYSCALL(munmap) DL_SYSCALL(mprotect) @@ -194,6 +195,7 @@ DL_SYSCALL(sendsyslog) DL_SYSCALL(pledge) DL_SYSCALL2(getcwd,__getcwd) DL_SYSCALL(sysctl) +DL_SYSCALL2_NOERR(set_tcb,__set_tcb) DL_SYSCALL(getdents) diff --git a/libexec/ld.so/sh/syscall.h b/libexec/ld.so/sh/syscall.h index e5069e066af..c98b8e11cec 100644 --- a/libexec/ld.so/sh/syscall.h +++ b/libexec/ld.so/sh/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.18 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.19 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); @@ -58,6 +59,7 @@ int _dl_getcwd(char *, size_t); int _dl_utrace(const char *, const void *, size_t); int _dl_getentropy(char *, size_t); int _dl_sendsyslog(const char *, size_t, int); +void _dl_set_tcb(void *); static inline off_t _dl_lseek(int fildes, off_t offset, int whence) diff --git a/libexec/ld.so/sparc/ldasm.S b/libexec/ld.so/sparc/ldasm.S index 3bcf14814fd..0d5788bb01c 100644 --- a/libexec/ld.so/sparc/ldasm.S +++ b/libexec/ld.so/sparc/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.30 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.31 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Jason L. Wright (jason@thought.net) @@ -176,6 +176,18 @@ _dl_issetugid: .section ".text" .align 4 + .global _dl_getthrid + .type _dl_getthrid,@function +_dl_getthrid: + mov SYS_getthrid | SYSCALL_G2RFLAG, %g1 ! call sys_getthrid + add %o7, 8, %g2 ! just return on success + t ST_SYSCALL ! off to wonderland + retl + sub %g0, %o0, %o0 ! error: result = -errno + + + .section ".text" + .align 4 .global _dl__syscall .type _dl__syscall,@function _dl__syscall: diff --git a/libexec/ld.so/sparc/syscall.h b/libexec/ld.so/sparc/syscall.h index df5293ba4ea..a1f1cff714c 100644 --- a/libexec/ld.so/sparc/syscall.h +++ b/libexec/ld.so/sparc/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.25 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.26 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S index 47949f6d7c5..d0f6aa7b2c5 100644 --- a/libexec/ld.so/sparc64/ldasm.S +++ b/libexec/ld.so/sparc64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.42 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: ldasm.S,v 1.43 2016/05/07 19:05:23 guenther Exp $ */ /* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */ /* @@ -230,6 +230,13 @@ _ENTRY(_dl_issetugid) retl sub %g0, %o0, %o0 ! error: result = -errno +_ENTRY(_dl_getthrid) + mov SYS_getthrid | SYSCALL_G2RFLAG, %g1 ! call sys_getthrid + add %o7, 8, %g2 ! just return on success + t ST_SYSCALL ! off to wonderland + retl + sub %g0, %o0, %o0 ! error: result = -errno + _ENTRY(_dl__syscall) mov SYS___syscall | SYSCALL_G2RFLAG, %g1 ! call sys___syscall add %o7, 8, %g2 ! just return on success diff --git a/libexec/ld.so/sparc64/syscall.h b/libexec/ld.so/sparc64/syscall.h index 0abb05b7314..6fc3aa31934 100644 --- a/libexec/ld.so/sparc64/syscall.h +++ b/libexec/ld.so/sparc64/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.32 2016/03/21 22:41:29 bluhm Exp $ */ +/* $OpenBSD: syscall.h,v 1.33 2016/05/07 19:05:23 guenther Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist @@ -42,6 +42,7 @@ int _dl_close(int); __dead int _dl_exit(int); int _dl_issetugid(void); +int _dl_getthrid(void); long _dl__syscall(quad_t, ...); int _dl_mprotect(const void *, size_t, int); int _dl_munmap(const void *, size_t); diff --git a/libexec/ld.so/tib.c b/libexec/ld.so/tib.c new file mode 100644 index 00000000000..ed190ea90ad --- /dev/null +++ b/libexec/ld.so/tib.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Thread Information Block (TIB) and Thread Local Storage (TLS) handling + * (the TCB, Thread Control Block, is part of the TIB) + */ + +#define _DYN_LOADER + +#include <sys/types.h> +#include <sys/exec_elf.h> + +#include <tib.h> + +#include "archdep.h" +#include "resolve.h" +#include "util.h" +#include "syscall.h" + +/* If we need the syscall, use our local syscall definition */ +#define __set_tcb(tcb) _dl_set_tcb(tcb) + + +static int static_tls_size; + +int _dl_tib_static_done; + +/* + * Allocate a TIB for passing to __tfork for a new thread. 'extra' + * is the amount of space to allocate on the side of the TIB opposite + * of the TLS data: before the TIB for variant 1 and after the TIB + * for variant 2. If non-zero, tib_thread is set to point to that area. + */ +void * +_dl_allocate_tib(size_t extra) +{ + char *base; + struct tib *tib; + char *thread = NULL; + struct elf_object *obj; + +#if TLS_VARIANT == 1 + /* round up the extra size to align the tib after it */ + extra = ELF_ROUND(extra, sizeof(void *)); + base = _dl_malloc(extra + sizeof *tib + static_tls_size); + tib = (struct tib *)(base + extra); + if (extra) + thread = base; +#define TLS_ADDR(tibp, offset) ((char *)(tibp) + sizeof(struct tib) + (offset)) + +#elif TLS_VARIANT == 2 + /* round up the tib size to align the extra area after it */ + base = _dl_malloc(ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN) + + extra + static_tls_size); + tib = (struct tib *)(base + static_tls_size); + if (extra) + thread = (char *)tib + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN); +#define TLS_ADDR(tibp, offset) ((char *)(tibp) - (offset)) + +#endif + + for (obj = _dl_objects; obj != NULL; obj = obj->next) { + if (obj->tls_msize != 0) { + char *addr = TLS_ADDR(tib, obj->tls_offset); + + _dl_memset(addr + obj->tls_fsize, 0, + obj->tls_msize - obj->tls_fsize); + if (obj->tls_static_data != NULL) + _dl_bcopy(obj->tls_static_data, addr, + obj->tls_fsize); + DL_DEB(("\t%s has index %u addr %p msize %u fsize %u\n", + obj->load_name, obj->tls_offset, + (void *)addr, obj->tls_msize, obj->tls_fsize)); + } + } + + TIB_INIT(tib, NULL, thread); + + DL_DEB(("tib new=%p\n", (void *)tib)); + + return (tib); +} + +void +_dl_free_tib(void *tib, size_t extra) +{ + size_t tib_offset; + +#if TLS_VARIANT == 1 + tib_offset = ELF_ROUND(extra, sizeof(void *)); +#elif TLS_VARIANT == 2 + tib_offset = static_tls_size; +#endif + + DL_DEB(("free tib=%p\n", (void *)tib)); + _dl_free((char *)tib - tib_offset); +} + + +/* + * Record what's necessary for handling TLS for an object. + */ +void +_dl_set_tls(elf_object_t *object, Elf_Phdr *ptls, Elf_Addr libaddr, + const char *libname) +{ + if (ptls->p_vaddr != 0 && ptls->p_filesz != 0) + object->tls_static_data = (void *)(ptls->p_vaddr + libaddr); + object->tls_fsize = ptls->p_filesz; + object->tls_msize = ptls->p_memsz; + object->tls_align = ptls->p_align; + + DL_DEB(("tls %x %x %x %x\n", + object->tls_static_data, object->tls_fsize, object->tls_msize, + object->tls_align)); +} + +static inline Elf_Addr +allocate_tls_offset(Elf_Addr msize, Elf_Addr align) +{ + Elf_Addr offset; + +#if TLS_VARIANT == 1 + /* round up to the required alignment, then allocate the space */ + offset = ELF_ROUND(static_tls_size, align); + static_tls_size += msize; +#elif TLS_VARIANT == 2 + /* + * allocate the space, then round up to the alignment + * (these are negative offsets, so rounding up really rounds the + * address down) + */ + static_tls_size = ELF_ROUND(static_tls_size + msize, align); + offset = static_tls_size; +#else +# error "unknown TLS_VARIANT" +#endif + return offset; +} + +/* + * Calculate the TLS offset for each object with static TLS. + */ +void +_dl_allocate_tls_offsets(void) +{ + struct elf_object *obj; + + for (obj = _dl_objects; obj != NULL; obj = obj->next) { + if (obj->tls_msize != 0) { + obj->tls_offset = allocate_tls_offset(obj->tls_msize, + obj->tls_align); + } + } + + /* no more static TLS allocations after this */ + _dl_tib_static_done = 1; +} + +/* + * Allocate the TIB + TLS for the initial thread. + */ +void +_dl_allocate_first_tib(void) +{ + struct tib *tib; + + tib = _dl_allocate_tib(0); + tib->tib_tid = _dl_getthrid(); + + TCB_SET(TIB_TO_TCB(tib)); +} |