diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2019-06-02 01:03:02 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2019-06-02 01:03:02 +0000 |
commit | 4a80a8ec4a5d6d7d4690398d18ba3e11a49f0d8d (patch) | |
tree | ba6f9621a1170d5b6b13543f937687973ef87a85 /lib | |
parent | a8565da1091ea7a7792ae6d3d19d0fa477404ab6 (diff) |
Complete the ld.so boot cleanup: move most libc initialization from
_csu_finish() to _libc_preinit(), which is an .init_array function
in shared libc (and mark it INITFIRST) or a .preinit_array function
in static libc, grabbing the _dl_cb callback there from ld.so. Then
in _csu_finish(), invoke the dl_clean_boot() callback to free ld.so's
startup bits before main() gets control.
Other cleanups this permits:
- move various startup structures into .data.rel.ro
- the dl* stubs in libc can be strong and call the callbacks provided
via _dl_cb
- no longer need to conditionalize dlctl() calls on presence of _DYNAMIC
original concept and full diff ok kettenis@
ok deraadt@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/Makefile | 3 | ||||
-rw-r--r-- | lib/libc/dlfcn/dlfcn_stubs.c | 43 | ||||
-rw-r--r-- | lib/libc/dlfcn/init.c | 83 | ||||
-rw-r--r-- | lib/libc/hidden/dlfcn.h | 30 | ||||
-rw-r--r-- | lib/libc/hidden/link_elf.h | 26 | ||||
-rw-r--r-- | lib/libc/hidden/tib.h | 5 | ||||
-rw-r--r-- | lib/libc/include/namespace.h | 4 | ||||
-rw-r--r-- | lib/libc/stdlib/thread_atexit.c | 9 |
8 files changed, 153 insertions, 50 deletions
diff --git a/lib/libc/Makefile b/lib/libc/Makefile index 891fdc7ee05..bd812632e37 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.40 2017/01/22 23:56:44 jsg Exp $ +# $OpenBSD: Makefile,v 1.41 2019/06/02 01:03:01 guenther Exp $ # # The YP functions are always in libc. To choose that getpwent() and friends # actually call the YP functions, put -DYP on the CFLAGS line below. @@ -16,6 +16,7 @@ LDADD+=-lcompiler_rt .else LDADD+=-lgcc .endif +LDADD+=-Wl,-zinitfirst VERSION_SCRIPT= Symbols.map SYMBOL_LISTS= ${LIBCSRCDIR}/Symbols.list \ diff --git a/lib/libc/dlfcn/dlfcn_stubs.c b/lib/libc/dlfcn/dlfcn_stubs.c index e04a2aa0706..78d728f66cb 100644 --- a/lib/libc/dlfcn/dlfcn_stubs.c +++ b/lib/libc/dlfcn/dlfcn_stubs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dlfcn_stubs.c,v 1.14 2016/09/06 18:49:34 guenther Exp $ */ +/* $OpenBSD: dlfcn_stubs.c,v 1.15 2019/06/02 01:03:01 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -28,34 +28,19 @@ #include <sys/types.h> #include <stddef.h> +#include <stdio.h> #include <link.h> +#include <dlfcn.h> +#include <tib.h> #include "init.h" -/* - * All functions here are just stubs that will be overridden - * by the real functions in ld.so when dynamic loading is - * performed at exec. The symbols here are provided as a link - * helper so we can link a program using the dl functions - * without getting any unresolved references. - */ - -void *dlopen(const char *libname, int how) __attribute__((weak)); -int dlclose(void *handle) __attribute__((weak)); -void *dlsym(void *handle, const char *name) __attribute__((weak)); -int dlctl(void *handle, int command, void *data) __attribute__((weak)); -char *dlerror(void) __attribute__((weak)); - -struct dl_info; -int dladdr(const void *addr, struct dl_info *info) __attribute__((weak)); - -int dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *date) __attribute__((weak)); - -#include <stdio.h> void * dlopen(const char *libname, int how) { + if (_dl_cb != NULL && _dl_cb->dlopen != NULL) + return _dl_cb->dlopen(libname, how); printf("Wrong dl symbols!\n"); return NULL; } @@ -63,6 +48,8 @@ dlopen(const char *libname, int how) int dlclose(void *handle) { + if (_dl_cb != NULL && _dl_cb->dlclose != NULL) + return _dl_cb->dlclose(handle); printf("Wrong dl symbols!\n"); return 0; } @@ -70,6 +57,8 @@ dlclose(void *handle) void * dlsym(void *handle, const char *name) { + if (_dl_cb != NULL && _dl_cb->dlsym != NULL) + return _dl_cb->dlsym(handle, name); printf("Wrong dl symbols!\n"); return NULL; } @@ -77,12 +66,17 @@ dlsym(void *handle, const char *name) int dlctl(void *handle, int command, void *data) { + if (_dl_cb != NULL && _dl_cb->dlctl != NULL) + return _dl_cb->dlctl(handle, command, data); return -1; } +DEF_WEAK(dlctl); char * dlerror(void) { + if (_dl_cb != NULL && _dl_cb->dlerror != NULL) + return _dl_cb->dlerror(); return "Wrong dl symbols!\n"; } @@ -90,6 +84,8 @@ int dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data) { + if (_dl_cb != NULL && _dl_cb->dl_iterate_phdr != NULL) + return _dl_cb->dl_iterate_phdr(callback, data); #ifndef PIC if (_static_phdr_info.dlpi_phdr != NULL) return callback(&_static_phdr_info, sizeof(_static_phdr_info), @@ -97,14 +93,18 @@ dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), #endif /* !PIC */ return -1; } +DEF_WEAK(dl_iterate_phdr); int dladdr(const void *addr, struct dl_info *info) { + if (_dl_cb != NULL && _dl_cb->dladdr != NULL) + return _dl_cb->dladdr(addr, info); printf("Wrong dl symbols!\n"); return -1; } +#if 0 /* Thread Local Storage argument structure */ typedef struct { unsigned long int ti_module; @@ -131,3 +131,4 @@ ___tls_get_addr(tls_index *ti) } #endif /* __i386 */ #endif /* arch with TLS support enabled */ +#endif diff --git a/lib/libc/dlfcn/init.c b/lib/libc/dlfcn/init.c index 3c387a60d6b..270f54aada5 100644 --- a/lib/libc/dlfcn/init.c +++ b/lib/libc/dlfcn/init.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init.c,v 1.6 2017/12/01 23:30:05 guenther Exp $ */ +/* $OpenBSD: init.c,v 1.7 2019/06/02 01:03:01 guenther Exp $ */ /* * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org> * @@ -57,7 +57,7 @@ char *__progname __attribute__((weak)) = NULL; #ifndef PIC -struct dl_phdr_info _static_phdr_info = { .dlpi_name = "a.out" }; +struct dl_phdr_info _static_phdr_info __relro = { .dlpi_name = "a.out" }; static inline void early_static_init(char **_argv, char **_envp); static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); @@ -66,13 +66,12 @@ static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum); extern Elf_Ehdr __executable_start[] __attribute__((weak)); #endif /* PIC */ -/* - * extract useful bits from the auxiliary vector and either - * a) register ld.so's cleanup in dynamic links, or - * b) init __progname, environ, and the TIB in static links. - */ -char *** -_csu_finish(char **argv, char **envp, void (*cleanup)(void)) +/* provide definitions for these */ +const dl_cb *_dl_cb __relro = NULL; + +void _libc_preinit(int, char **, char **, dl_cb_cb *) __dso_hidden; +void +_libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb) { AuxInfo *aux; #ifndef PIC @@ -80,10 +79,13 @@ _csu_finish(char **argv, char **envp, void (*cleanup)(void)) int phnum = 0; /* static libc in a static link? */ - if (cleanup == NULL) + if (cb == NULL) early_static_init(argv, envp); #endif /* !PIC */ + if (cb != NULL) + _dl_cb = cb(DL_CB_CUR); + /* Extract useful bits from the auxiliary vector */ while (*envp++ != NULL) ; @@ -98,30 +100,73 @@ _csu_finish(char **argv, char **envp, void (*cleanup)(void)) break; case AUX_phdr: phdr = (void *)aux->au_v; - _static_phdr_info.dlpi_phdr = phdr; break; case AUX_phnum: phnum = aux->au_v; - _static_phdr_info.dlpi_phnum = phnum; break; #endif /* !PIC */ } } #ifndef PIC - if (cleanup == NULL && phdr == NULL && __executable_start != NULL) { + if (cb == NULL && phdr == NULL && __executable_start != NULL) { /* * Static non-PIE processes don't get an AUX vector, * so find the phdrs through the ELF header */ + _static_phdr_info.dlpi_addr = (Elf_Addr)__executable_start; phdr = (void *)((char *)__executable_start + __executable_start->e_phoff); phnum = __executable_start->e_phnum; } + _static_phdr_info.dlpi_phdr = phdr; + _static_phdr_info.dlpi_phnum = phnum; + /* static libc in a static link? */ - if (cleanup == NULL) + if (cb == NULL) setup_static_tib(phdr, phnum); #endif /* !PIC */ +} + +/* ARM just had to be different... */ +#ifndef __arm__ +# define TYPE "@" +#else +# define TYPE "%" +#endif + +#ifdef __LP64__ +# define VALUE_ALIGN ".balign 8" +# define VALUE_DIRECTIVE ".quad" +#else +# define VALUE_ALIGN ".balign 4" +# ifdef __hppa__ + /* hppa just had to be different: func pointers prefix with 'P%' */ +# define VALUE_DIRECTIVE ".int P%" +# else +# define VALUE_DIRECTIVE ".int" +# endif +#endif + +#define ADD_TO_ARRAY(func, which) \ + __asm( " .section ."#which",\"a\","TYPE#which"\n " \ + VALUE_ALIGN"\n "VALUE_DIRECTIVE" "#func"\n .previous") + +#ifdef PIC +ADD_TO_ARRAY(_libc_preinit, init_array); +#else +ADD_TO_ARRAY(_libc_preinit, preinit_array); +#endif + +/* + * In dynamic links, invoke ld.so's dl_clean_boot() callback, if any, + * and register its cleanup. + */ +char *** +_csu_finish(char **argv, char **envp, void (*cleanup)(void)) +{ + if (_dl_cb != NULL && _dl_cb->dl_clean_boot != NULL) + _dl_cb->dl_clean_boot(); if (cleanup != NULL) atexit(cleanup); @@ -163,12 +208,12 @@ early_static_init(char **argv, char **envp) #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) /* for static binaries, the location and size of the TLS image */ -static void *static_tls; -static size_t static_tls_fsize; +static void *static_tls __relro; +static size_t static_tls_fsize __relro; -size_t _static_tls_size = 0; -int _static_tls_align; -int _static_tls_align_offset; +size_t _static_tls_size __relro = 0; +int _static_tls_align __relro; +int _static_tls_align_offset __relro; static inline void setup_static_tib(Elf_Phdr *phdr, int phnum) diff --git a/lib/libc/hidden/dlfcn.h b/lib/libc/hidden/dlfcn.h new file mode 100644 index 00000000000..bb6dc23c266 --- /dev/null +++ b/lib/libc/hidden/dlfcn.h @@ -0,0 +1,30 @@ +/* $OpenBSD: dlfcn.h,v 1.1 2019/06/02 01:03:01 guenther Exp $ */ +/* + * Copyright (c) 2019 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. + */ + +#ifndef _LIBC_DLFCN_H_ +#define _LIBC_DLFCN_H_ + +#include_next <dlfcn.h> + +PROTO_DEPRECATED(dladdr); +PROTO_DEPRECATED(dlclose); +PROTO_DEPRECATED(dlerror); +PROTO_DEPRECATED(dlopen); +PROTO_DEPRECATED(dlsym); +PROTO_NORMAL(dlctl); + +#endif /* _LIBC_DLFCN_H_ */ diff --git a/lib/libc/hidden/link_elf.h b/lib/libc/hidden/link_elf.h new file mode 100644 index 00000000000..04143ec91d2 --- /dev/null +++ b/lib/libc/hidden/link_elf.h @@ -0,0 +1,26 @@ +/* $OpenBSD: link_elf.h,v 1.1 2019/06/02 01:03:01 guenther Exp $ */ +/* + * Copyright (c) 2019 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. + */ + +#ifndef _LIBC_LINK_ELF_H_ +#define _LIBC_LINK_ELF_H_ + +#include_next <link_elf.h> + +PROTO_NORMAL(dl_iterate_phdr); +PROTO_DEPRECATED(dl_unwind_find_exidx); + +#endif /* _LIBC_LINK_ELF_H_ */ diff --git a/lib/libc/hidden/tib.h b/lib/libc/hidden/tib.h index 9c4be95fb96..26463db020c 100644 --- a/lib/libc/hidden/tib.h +++ b/lib/libc/hidden/tib.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tib.h,v 1.2 2017/12/01 23:30:05 guenther Exp $ */ +/* $OpenBSD: tib.h,v 1.3 2019/06/02 01:03:01 guenther Exp $ */ /* * Copyright (c) 2015 Philip Guenther <guenther@openbsd.org> * @@ -39,6 +39,9 @@ extern int _static_tls_align; extern int _static_tls_align_offset; #endif +/* saved handle to callbacks from ld.so */ +extern const dl_cb *_dl_cb; + #if ! TCB_HAVE_MD_GET /* * For archs without a fast TCB_GET(): the pointer to the TCB in diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h index 79692af0bca..330af4050ad 100644 --- a/lib/libc/include/namespace.h +++ b/lib/libc/include/namespace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: namespace.h,v 1.13 2019/05/13 20:00:32 guenther Exp $ */ +/* $OpenBSD: namespace.h,v 1.14 2019/06/02 01:03:01 guenther Exp $ */ #ifndef _LIBC_NAMESPACE_H_ #define _LIBC_NAMESPACE_H_ @@ -59,6 +59,8 @@ #define MAKE_CLONE(dst, src) __dso_hidden typeof(dst) HIDDEN(dst) \ __attribute__((alias (HIDDEN_STRING(src)))) +#define __relro __attribute__((section(".data.rel.ro"))) + /* * gcc and clang will generate calls to the functions below. diff --git a/lib/libc/stdlib/thread_atexit.c b/lib/libc/stdlib/thread_atexit.c index 2e00428eba4..ef0423c4284 100644 --- a/lib/libc/stdlib/thread_atexit.c +++ b/lib/libc/stdlib/thread_atexit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: thread_atexit.c,v 1.1 2017/12/16 20:06:56 guenther Exp $ */ +/* $OpenBSD: thread_atexit.c,v 1.2 2019/06/02 01:03:01 guenther Exp $ */ /* * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> * @@ -16,15 +16,11 @@ */ #include <dlfcn.h> -#include <elf.h> -#pragma weak _DYNAMIC #include <stdlib.h> #include <tib.h> #include "atexit.h" -typeof(dlctl) dlctl asm("_dlctl") __attribute__((weak)); - __weak_alias(__cxa_thread_atexit, __cxa_thread_atexit_impl); int @@ -37,8 +33,7 @@ __cxa_thread_atexit_impl(void (*func)(void *), void *arg, void *dso) if (fnp == NULL) return -1; - if (_DYNAMIC) - dlctl(NULL, DL_REFERENCE, dso); + dlctl(NULL, DL_REFERENCE, dso); fnp->func = func; fnp->arg = arg; |