summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorLuiz Otavio O Souza <luiz@netgate.com>2017-02-09 12:56:45 -0600
committerLuiz Otavio O Souza <luiz@netgate.com>2017-02-09 12:56:45 -0600
commit91168d55b893d0ff41403098765ffb6a890805a0 (patch)
tree429fd0d8430d5b8140c527d92b60fbb3fe2e2278 /libexec
parentac4b1285e0aabc7a59f32412b4f2ca7674c5458f (diff)
parent9077a30ba0ad5458cceb3d0418b2f1ea7f70d556 (diff)
downloadFreeBSD-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.h4
-rw-r--r--libexec/rtld-elf/amd64/rtld_start.S12
-rw-r--r--libexec/rtld-elf/rtld.c123
-rw-r--r--libexec/rtld-elf/rtld.h5
-rw-r--r--libexec/rtld-elf/rtld_lock.c61
-rw-r--r--libexec/tftpd/Makefile5
-rw-r--r--libexec/tftpd/tftpd.c7
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
OpenPOWER on IntegriCloud