diff options
author | Luiz Otavio O Souza <luiz@netgate.com> | 2017-02-09 12:56:45 -0600 |
---|---|---|
committer | Luiz Otavio O Souza <luiz@netgate.com> | 2017-02-09 12:56:45 -0600 |
commit | 91168d55b893d0ff41403098765ffb6a890805a0 (patch) | |
tree | 429fd0d8430d5b8140c527d92b60fbb3fe2e2278 /libexec | |
parent | ac4b1285e0aabc7a59f32412b4f2ca7674c5458f (diff) | |
parent | 9077a30ba0ad5458cceb3d0418b2f1ea7f70d556 (diff) | |
download | FreeBSD-src-91168d55b893d0ff41403098765ffb6a890805a0.zip FreeBSD-src-91168d55b893d0ff41403098765ffb6a890805a0.tar.gz |
Merge remote-tracking branch 'origin/stable/11' into devel-11
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/amd64/rtld_machdep.h | 4 | ||||
-rw-r--r-- | libexec/rtld-elf/amd64/rtld_start.S | 12 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.c | 123 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.h | 5 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld_lock.c | 61 | ||||
-rw-r--r-- | libexec/tftpd/Makefile | 5 | ||||
-rw-r--r-- | libexec/tftpd/tftpd.c | 7 |
7 files changed, 159 insertions, 58 deletions
diff --git a/libexec/rtld-elf/amd64/rtld_machdep.h b/libexec/rtld-elf/amd64/rtld_machdep.h index df6fc33..0a6354f 100644 --- a/libexec/rtld-elf/amd64/rtld_machdep.h +++ b/libexec/rtld-elf/amd64/rtld_machdep.h @@ -35,8 +35,8 @@ struct Struct_Obj_Entry; /* Return the address of the .dynamic section in the dynamic linker. */ -#define rtld_dynamic(obj) \ - ((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC)) +Elf_Dyn *rtld_dynamic_addr(void); +#define rtld_dynamic(obj) rtld_dynamic_addr() /* Fixup the jump slot at "where" to transfer control to "target". */ static inline Elf_Addr diff --git a/libexec/rtld-elf/amd64/rtld_start.S b/libexec/rtld-elf/amd64/rtld_start.S index 387d26c..72240a9 100644 --- a/libexec/rtld-elf/amd64/rtld_start.S +++ b/libexec/rtld-elf/amd64/rtld_start.S @@ -156,4 +156,16 @@ _rtld_bind_start: .cfi_endproc .size _rtld_bind_start, . - _rtld_bind_start + .align 4 + .globl rtld_dynamic_addr + .type rtld_dynamic_addr,@function +rtld_dynamic_addr: + .cfi_startproc + .weak _DYNAMIC + .hidden _DYNAMIC + lea _DYNAMIC(%rip),%rax + ret + .cfi_endproc + .size rtld_dynamic_addr, . - rtld_dynamic_addr + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 3b40d39..f75bcad 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -87,7 +87,10 @@ static char *errmsg_save(void); static void *fill_search_info(const char *, size_t, void *); static char *find_library(const char *, const Obj_Entry *, int *); static const char *gethints(bool); +static void hold_object(Obj_Entry *); +static void unhold_object(Obj_Entry *); static void init_dag(Obj_Entry *); +static void init_marker(Obj_Entry *); static void init_pagesizes(Elf_Auxinfo **aux_info); static void init_rtld(caddr_t, Elf_Auxinfo **); static void initlist_add_neededs(Needed_Entry *, Objlist *); @@ -100,6 +103,7 @@ static int load_needed_objects(Obj_Entry *, int); static int load_preload_objects(void); static Obj_Entry *load_object(const char *, int fd, const Obj_Entry *, int); static void map_stacks_exec(RtldLockState *); +static int obj_enforce_relro(Obj_Entry *); static Obj_Entry *obj_from_addr(const void *); static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *); static void objlist_call_init(Objlist *, RtldLockState *); @@ -112,6 +116,7 @@ static void objlist_put_after(Objlist *, Obj_Entry *, Obj_Entry *); static void objlist_remove(Objlist *, Obj_Entry *); static int parse_libdir(const char *); static void *path_enumerate(const char *, path_enum_proc, void *); +static void release_object(Obj_Entry *); static int relocate_object_dag(Obj_Entry *root, bool bind_now, Obj_Entry *rtldobj, int flags, RtldLockState *lockstate); static int relocate_object(Obj_Entry *obj, bool bind_now, Obj_Entry *rtldobj, @@ -613,6 +618,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (do_copy_relocations(obj_main) == -1) rtld_die(); + dbg("enforcing main obj relro"); + if (obj_enforce_relro(obj_main) == -1) + rtld_die(); + if (getenv(_LD("DUMP_REL_POST")) != NULL) { dump_relocations(obj_main); exit (0); @@ -1822,6 +1831,14 @@ init_dag(Obj_Entry *root) root->dag_inited = true; } +static void +init_marker(Obj_Entry *marker) +{ + + bzero(marker, sizeof(*marker)); + marker->marker = true; +} + Obj_Entry * globallist_curr(const Obj_Entry *obj) { @@ -1848,6 +1865,23 @@ globallist_next(const Obj_Entry *obj) } } +/* Prevent the object from being unmapped while the bind lock is dropped. */ +static void +hold_object(Obj_Entry *obj) +{ + + obj->holdcount++; +} + +static void +unhold_object(Obj_Entry *obj) +{ + + assert(obj->holdcount > 0); + if (--obj->holdcount == 0 && obj->unholdfree) + release_object(obj); +} + static void process_z(Obj_Entry *root) { @@ -2205,7 +2239,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) fd = -1; if (name != NULL) { TAILQ_FOREACH(obj, &obj_list, next) { - if (obj->marker) + if (obj->marker || obj->doomed) continue; if (object_match_name(obj, name)) return (obj); @@ -2252,7 +2286,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) return NULL; } TAILQ_FOREACH(obj, &obj_list, next) { - if (obj->marker) + if (obj->marker || obj->doomed) continue; if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) break; @@ -2394,6 +2428,9 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) assert(root == NULL || root->refcount == 1); + if (root != NULL) + root->doomed = true; + /* * Preserve the current error message since a fini function might * call into the dynamic linker and overwrite it. @@ -2406,15 +2443,11 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) continue; /* Remove object from fini list to prevent recursive invocation. */ STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link); - /* - * XXX: If a dlopen() call references an object while the - * fini function is in progress, we might end up trying to - * unload the referenced object in dlclose() or the object - * won't be unloaded although its fini function has been - * called. - */ - lock_release(rtld_bind_lock, lockstate); + /* Ensure that new references cannot be acquired. */ + elm->obj->doomed = true; + hold_object(elm->obj); + lock_release(rtld_bind_lock, lockstate); /* * It is legal to have both DT_FINI and DT_FINI_ARRAY defined. * When this happens, DT_FINI_ARRAY is processed first. @@ -2440,6 +2473,7 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) call_initfini_pointer(elm->obj, elm->obj->fini); } wlock_acquire(rtld_bind_lock, lockstate); + unhold_object(elm->obj); /* No need to free anything if process is going down. */ if (root != NULL) free(elm); @@ -2493,6 +2527,7 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate) * without better locking. */ elm->obj->init_done = true; + hold_object(elm->obj); lock_release(rtld_bind_lock, lockstate); /* @@ -2519,6 +2554,7 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate) } } wlock_acquire(rtld_bind_lock, lockstate); + unhold_object(elm->obj); } errmsg_restore(saved_msg); } @@ -2711,14 +2747,8 @@ relocate_object(Obj_Entry *obj, bool bind_now, Obj_Entry *rtldobj, reloc_non_plt(obj, rtldobj, flags | SYMLOOK_IFUNC, lockstate)) return (-1); - if (obj->relro_size > 0) { - if (mprotect(obj->relro_page, obj->relro_size, - PROT_READ) == -1) { - _rtld_error("%s: Cannot enforce relro protection: %s", - obj->path, rtld_strerror(errno)); - return (-1); - } - } + if (!obj->mainprog && obj_enforce_relro(obj) == -1) + return (-1); /* * Set up the magic number and version in the Obj_Entry. These @@ -3540,8 +3570,7 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) RtldLockState bind_lockstate, phdr_lockstate; int error; - bzero(&marker, sizeof(marker)); - marker.marker = true; + init_marker(&marker); error = 0; wlock_acquire(rtld_phdr_lock, &phdr_lockstate); @@ -3549,11 +3578,13 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) for (obj = globallist_curr(TAILQ_FIRST(&obj_list)); obj != NULL;) { TAILQ_INSERT_AFTER(&obj_list, obj, &marker, next); rtld_fill_dl_phdr_info(obj, &phdr_info); + hold_object(obj); lock_release(rtld_bind_lock, &bind_lockstate); error = callback(&phdr_info, sizeof phdr_info, param); wlock_acquire(rtld_bind_lock, &bind_lockstate); + unhold_object(obj); obj = globallist_next(&marker); TAILQ_REMOVE(&obj_list, &marker, next); if (error != 0) { @@ -3808,6 +3839,19 @@ _r_debug_postinit(struct link_map *m) __compiler_membar(); } +static void +release_object(Obj_Entry *obj) +{ + + if (obj->holdcount > 0) { + obj->unholdfree = true; + return; + } + munmap(obj->mapbase, obj->mapsize); + linkmap_delete(obj); + obj_free(obj); +} + /* * Get address of the pointer variable in the main program. * Prefer non-weak symbol over the weak one. @@ -4378,7 +4422,7 @@ trace_loaded_objects(Obj_Entry *obj) static void unload_object(Obj_Entry *root) { - Obj_Entry *obj, *obj1; + Obj_Entry marker, *obj, *next; assert(root->refcount == 0); @@ -4389,18 +4433,32 @@ unload_object(Obj_Entry *root) unlink_object(root); /* Unmap all objects that are no longer referenced. */ - TAILQ_FOREACH_SAFE(obj, &obj_list, next, obj1) { + for (obj = TAILQ_FIRST(&obj_list); obj != NULL; obj = next) { + next = TAILQ_NEXT(obj, next); if (obj->marker || obj->refcount != 0) continue; LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, obj->path); dbg("unloading \"%s\"", obj->path); - unload_filtees(root); - munmap(obj->mapbase, obj->mapsize); - linkmap_delete(obj); + /* + * Unlink the object now to prevent new references from + * being acquired while the bind lock is dropped in + * recursive dlclose() invocations. + */ TAILQ_REMOVE(&obj_list, obj, next); obj_count--; - obj_free(obj); + + if (obj->filtees_loaded) { + if (next != NULL) { + init_marker(&marker); + TAILQ_INSERT_BEFORE(next, &marker, next); + unload_filtees(obj); + next = TAILQ_NEXT(&marker, next); + TAILQ_REMOVE(&obj_list, &marker, next); + } else + unload_filtees(obj); + } + release_object(obj); } } @@ -5061,6 +5119,19 @@ _rtld_is_dlopened(void *arg) return (res); } +int +obj_enforce_relro(Obj_Entry *obj) +{ + + if (obj->relro_size > 0 && mprotect(obj->relro_page, obj->relro_size, + PROT_READ) == -1) { + _rtld_error("%s: Cannot enforce relro protection: %s", + obj->path, rtld_strerror(errno)); + return (-1); + } + return (0); +} + static void map_stacks_exec(RtldLockState *lockstate) { diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index afdf83a..4e48026 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -142,7 +142,8 @@ typedef struct Struct_Obj_Entry { TAILQ_ENTRY(Struct_Obj_Entry) next; char *path; /* Pathname of underlying file (%) */ char *origin_path; /* Directory path of origin file */ - int refcount; + int refcount; /* DAG references */ + int holdcount; /* Count of transient references */ int dl_refcount; /* Number of times loaded by dlopen */ /* These items are computed by map_object() or by digest_phdr(). */ @@ -265,6 +266,8 @@ typedef struct Struct_Obj_Entry { bool valid_hash_gnu : 1; /* A valid GNU hash tag is available */ bool dlopened : 1; /* dlopen()-ed (vs. load statically) */ bool marker : 1; /* marker on the global obj list */ + bool unholdfree : 1; /* unmap upon last unhold */ + bool doomed : 1; /* Object cannot be referenced */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c index f31546c..c4d2a0b 100644 --- a/libexec/rtld-elf/rtld_lock.c +++ b/libexec/rtld-elf/rtld_lock.c @@ -38,8 +38,8 @@ * In this algorithm the lock is a single word. Its low-order bit is * set when a writer holds the lock. The remaining high-order bits * contain a count of readers desiring the lock. The algorithm requires - * atomic "compare_and_store" and "add" operations, which we implement - * using assembly language sequences in "rtld_start.S". + * atomic "compare_and_store" and "add" operations, which we take + * from machine/atomic.h. */ #include <sys/param.h> @@ -64,10 +64,10 @@ typedef struct Struct_Lock { } Lock; static sigset_t fullsigmask, oldsigmask; -static int thread_flag; +static int thread_flag, wnested; static void * -def_lock_create() +def_lock_create(void) { void *base; char *p; @@ -117,29 +117,34 @@ def_rlock_acquire(void *lock) static void def_wlock_acquire(void *lock) { - Lock *l = (Lock *)lock; - sigset_t tmp_oldsigmask; + Lock *l; + sigset_t tmp_oldsigmask; - for ( ; ; ) { - sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask); - if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) - break; - sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL); - } - oldsigmask = tmp_oldsigmask; + l = (Lock *)lock; + for (;;) { + sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask); + if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) + break; + sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL); + } + if (atomic_fetchadd_int(&wnested, 1) == 0) + oldsigmask = tmp_oldsigmask; } static void def_lock_release(void *lock) { - Lock *l = (Lock *)lock; - - if ((l->lock & WAFLAG) == 0) - atomic_add_rel_int(&l->lock, -RC_INCR); - else { - atomic_add_rel_int(&l->lock, -WAFLAG); - sigprocmask(SIG_SETMASK, &oldsigmask, NULL); - } + Lock *l; + + l = (Lock *)lock; + if ((l->lock & WAFLAG) == 0) + atomic_add_rel_int(&l->lock, -RC_INCR); + else { + assert(wnested > 0); + atomic_add_rel_int(&l->lock, -WAFLAG); + if (atomic_fetchadd_int(&wnested, -1) == 1) + sigprocmask(SIG_SETMASK, &oldsigmask, NULL); + } } static int @@ -269,7 +274,7 @@ lock_restart_for_upgrade(RtldLockState *lockstate) } void -lockdflt_init() +lockdflt_init(void) { int i; @@ -373,12 +378,12 @@ _rtld_atfork_pre(int *locks) return; /* - * Warning: this does not work with the rtld compat locks - * above, since the thread signal mask is corrupted (set to - * all signals blocked) if two locks are taken in write mode. - * The caller of the _rtld_atfork_pre() must provide the - * working implementation of the locks, and libthr locks are - * fine. + * Warning: this did not worked well with the rtld compat + * locks above, when the thread signal mask was corrupted (set + * to all signals blocked) if two locks were taken + * simultaneously in the write mode. The caller of the + * _rtld_atfork_pre() must provide the working implementation + * of the locks anyway, and libthr locks are fine. */ wlock_acquire(rtld_phdr_lock, &ls[0]); wlock_acquire(rtld_bind_lock, &ls[1]); diff --git a/libexec/tftpd/Makefile b/libexec/tftpd/Makefile index 015458c..6f74a29 100644 --- a/libexec/tftpd/Makefile +++ b/libexec/tftpd/Makefile @@ -1,12 +1,17 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD$ +.include <src.opts.mk> + PROG= tftpd MAN= tftpd.8 SRCS= tftp-file.c tftp-io.c tftp-options.c tftp-transfer.c tftp-utils.c SRCS+= tftpd.c WFORMAT=0 +.if ${MK_TCP_WRAPPERS} != "no" +CFLAGS+= -DLIBWRAP LIBADD= wrap +.endif .include <bsd.prog.mk> diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c index 571fa59..26d8105 100644 --- a/libexec/tftpd/tftpd.c +++ b/libexec/tftpd/tftpd.c @@ -66,7 +66,6 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <syslog.h> -#include <tcpd.h> #include <unistd.h> #include "tftp-file.h" @@ -75,6 +74,10 @@ __FBSDID("$FreeBSD$"); #include "tftp-transfer.h" #include "tftp-options.h" +#ifdef LIBWRAP +#include <tcpd.h> +#endif + static void tftp_wrq(int peer, char *, ssize_t); static void tftp_rrq(int peer, char *, ssize_t); @@ -281,6 +284,7 @@ main(int argc, char *argv[]) } } +#ifdef LIBWRAP /* * See if the client is allowed to talk to me. * (This needs to be done before the chroot()) @@ -329,6 +333,7 @@ main(int argc, char *argv[]) "Full access allowed" "in /etc/hosts.allow"); } +#endif /* * Since we exit here, we should do that only after the above |