summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorskrll <skrll@NetBSD.org>2010-12-24 12:41:42 +0000
committerskrll <skrll@NetBSD.org>2010-12-24 12:41:42 +0000
commit3cd6f36785365945ee7cc808cdb0d6f5396d4fcf (patch)
tree4d32293a7d5147e62a2f594e98b9c3dadaf13225 /libexec
parentacf15340b17d10b7a16cd58703a258f2bfc8073a (diff)
Add support for DF_1_BIND_NOW, DF_1_NODELETE and DF_1_NOOPEN marked
objects, and the RTLD_NODELETE and RTLD_NOLOAD flags to dlopen(3). Mark libpthread as DF_1_NOOPEN and use it to test the functionality. Somewhat taken from FreeBSD. Fixes PR 42029. OK from christos and joerg.
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ld.elf_so/headers.c12
-rw-r--r--libexec/ld.elf_so/load.c49
-rw-r--r--libexec/ld.elf_so/reloc.c6
-rw-r--r--libexec/ld.elf_so/rtld.c55
-rw-r--r--libexec/ld.elf_so/rtld.h24
-rw-r--r--libexec/ld.elf_so/search.c29
6 files changed, 137 insertions, 38 deletions
diff --git a/libexec/ld.elf_so/headers.c b/libexec/ld.elf_so/headers.c
index 01a07d4a2a6..af4431fc9cc 100644
--- a/libexec/ld.elf_so/headers.c
+++ b/libexec/ld.elf_so/headers.c
@@ -1,4 +1,4 @@
-/* $NetBSD: headers.c,v 1.37 2010/10/16 17:48:12 skrll Exp $ */
+/* $NetBSD: headers.c,v 1.38 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: headers.c,v 1.37 2010/10/16 17:48:12 skrll Exp $");
+__RCSID("$NetBSD: headers.c,v 1.38 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
@@ -242,8 +242,14 @@ _rtld_digest_dynamic(const char *execname, Obj_Entry *obj)
break;
#endif
case DT_FLAGS_1:
- obj->initfirst =
+ obj->z_now =
+ ((dynp->d_un.d_val & DF_1_BIND_NOW) != 0);
+ obj->z_nodelete =
+ ((dynp->d_un.d_val & DF_1_NODELETE) != 0);
+ obj->z_initfirst =
((dynp->d_un.d_val & DF_1_INITFIRST) != 0);
+ obj->z_noopen =
+ ((dynp->d_un.d_val & DF_1_NOOPEN) != 0);
break;
}
}
diff --git a/libexec/ld.elf_so/load.c b/libexec/ld.elf_so/load.c
index 5fb3406a5ec..cefda1edb36 100644
--- a/libexec/ld.elf_so/load.c
+++ b/libexec/ld.elf_so/load.c
@@ -1,4 +1,4 @@
-/* $NetBSD: load.c,v 1.41 2010/12/19 17:26:51 skrll Exp $ */
+/* $NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: load.c,v 1.41 2010/12/19 17:26:51 skrll Exp $");
+__RCSID("$NetBSD: load.c,v 1.42 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
@@ -109,7 +109,7 @@ _rtld_objlist_find(Objlist *list, const Obj_Entry *obj)
* on failure.
*/
Obj_Entry *
-_rtld_load_object(const char *filepath, int mode)
+_rtld_load_object(const char *filepath, int flags)
{
Obj_Entry *obj;
int fd = -1;
@@ -153,6 +153,18 @@ _rtld_load_object(const char *filepath, int mode)
return NULL;
_rtld_digest_dynamic(filepath, obj);
+ if (flags & _RTLD_DLOPEN) {
+ if (obj->z_noopen || (flags & _RTLD_NOLOAD)) {
+ dbg(("refusing to load non-loadable \"%s\"",
+ obj->path));
+ _rtld_error("Cannot dlopen non-loadable %s",
+ obj->path);
+ munmap(obj->mapbase, obj->mapsize);
+ _rtld_obj_free(obj);
+ return OBJ_ERR;
+ }
+ }
+
*_rtld_objtail = obj;
_rtld_objtail = &obj->next;
_rtld_objcount++;
@@ -168,12 +180,12 @@ _rtld_load_object(const char *filepath, int mode)
++obj->refcount;
#ifdef RTLD_LOADER
- if (mode & RTLD_MAIN && !obj->mainref) {
+ if (flags & _RTLD_MAIN && !obj->mainref) {
obj->mainref = 1;
dbg(("adding %p (%s) to _rtld_list_main", obj, obj->path));
_rtld_objlist_push_tail(&_rtld_list_main, obj);
}
- if (mode & RTLD_GLOBAL && !obj->globalref) {
+ if (flags & _RTLD_GLOBAL && !obj->globalref) {
obj->globalref = 1;
dbg(("adding %p (%s) to _rtld_list_global", obj, obj->path));
_rtld_objlist_push_tail(&_rtld_list_global, obj);
@@ -183,7 +195,8 @@ _rtld_load_object(const char *filepath, int mode)
}
static bool
-_rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int mode)
+_rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed,
+ int flags)
{
Library_Xform *x = _rtld_xforms;
Obj_Entry *o = NULL;
@@ -240,7 +253,7 @@ _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int
for (j = 0; j < RTLD_MAX_LIBRARY &&
x->entry[i].library[j] != NULL; j++) {
o = _rtld_load_library(x->entry[i].library[j], obj,
- mode);
+ flags);
if (o == NULL) {
xwarnx("could not load %s for %s",
x->entry[i].library[j], name);
@@ -266,7 +279,7 @@ _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int
if (got)
return true;
- return ((*needed)->obj = _rtld_load_library(name, obj, mode)) != NULL;
+ return ((*needed)->obj = _rtld_load_library(name, obj, flags)) != NULL;
}
@@ -276,7 +289,7 @@ _rtld_load_by_name(const char *name, Obj_Entry *obj, Needed_Entry **needed, int
* returns -1 on failure.
*/
int
-_rtld_load_needed_objects(Obj_Entry *first, int mode)
+_rtld_load_needed_objects(Obj_Entry *first, int flags)
{
Obj_Entry *obj;
int status = 0;
@@ -287,11 +300,25 @@ _rtld_load_needed_objects(Obj_Entry *first, int mode)
for (needed = obj->needed; needed != NULL;
needed = needed->next) {
const char *name = obj->strtab + needed->name;
- if (!_rtld_load_by_name(name, obj, &needed, mode))
+#ifdef RTLD_LOADER
+ Obj_Entry *nobj;
+#endif
+ if (!_rtld_load_by_name(name, obj, &needed,
+ flags & ~_RTLD_NOLOAD))
status = -1; /* FIXME - cleanup */
#ifdef RTLD_LOADER
if (status == -1)
return status;
+
+ if (flags & _RTLD_MAIN)
+ continue;
+
+ nobj = needed->obj;
+ if (nobj->z_nodelete && !obj->ref_nodel) {
+ dbg(("obj %s nodelete", nobj->path));
+ _rtld_ref_dag(nobj);
+ nobj->ref_nodel = true;
+ }
#endif
}
}
@@ -310,7 +337,7 @@ _rtld_preload(const char *preload_path)
if (preload_path != NULL && *preload_path != '\0') {
cp = buf = xstrdup(preload_path);
while ((path = strsep(&cp, " :")) != NULL && status == 0) {
- if (!_rtld_load_object(path, RTLD_MAIN))
+ if (!_rtld_load_object(path, _RTLD_MAIN))
status = -1;
else
dbg((" preloaded \"%s\"", path));
diff --git a/libexec/ld.elf_so/reloc.c b/libexec/ld.elf_so/reloc.c
index 7ed763b0d43..c0666b2111c 100644
--- a/libexec/ld.elf_so/reloc.c
+++ b/libexec/ld.elf_so/reloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: reloc.c,v 1.102 2010/04/05 14:01:26 joerg Exp $ */
+/* $NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@@ -39,7 +39,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: reloc.c,v 1.102 2010/04/05 14:01:26 joerg Exp $");
+__RCSID("$NetBSD: reloc.c,v 1.103 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
@@ -195,7 +195,7 @@ _rtld_relocate_objects(Obj_Entry *first, bool bind_now)
#if defined(__hppa__)
bind_now = 1;
#endif
- if (bind_now) {
+ if (obj->z_now || bind_now) {
dbg(("doing immediate PLT binding"));
if (_rtld_relocate_plt_objects(obj) < 0)
ok = 0;
diff --git a/libexec/ld.elf_so/rtld.c b/libexec/ld.elf_so/rtld.c
index 3047930d151..24528c387a3 100644
--- a/libexec/ld.elf_so/rtld.c
+++ b/libexec/ld.elf_so/rtld.c
@@ -1,4 +1,4 @@
-/* $NetBSD: rtld.c,v 1.136 2010/12/19 17:26:51 skrll Exp $ */
+/* $NetBSD: rtld.c,v 1.137 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.136 2010/12/19 17:26:51 skrll Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.137 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
@@ -147,7 +147,7 @@ _rtld_call_fini_functions(int force)
if (obj->refcount > 0 && !force) {
continue;
}
- if (obj->fini == NULL || obj->fini_called || obj->initfirst) {
+ if (obj->fini == NULL || obj->fini_called || obj->z_initfirst) {
continue;
}
dbg (("calling fini function %s at %p", obj->path,
@@ -188,7 +188,7 @@ _rtld_call_init_functions()
/* First pass: objects marked with DF_1_INITFIRST. */
SIMPLEQ_FOREACH(elm, &initlist, link) {
obj = elm->obj;
- if (obj->init == NULL || obj->init_called || !obj->initfirst) {
+ if (obj->init == NULL || obj->init_called || !obj->z_initfirst) {
continue;
}
dbg (("calling init function %s at %p (DF_1_INITFIRST)",
@@ -568,7 +568,7 @@ _rtld(Elf_Addr *sp, Elf_Addr relocbase)
}
dbg(("loading needed objects"));
- if (_rtld_load_needed_objects(_rtld_objmain, RTLD_MAIN) == -1)
+ if (_rtld_load_needed_objects(_rtld_objmain, _RTLD_MAIN) == -1)
_rtld_die();
dbg(("relocating objects"));
@@ -760,13 +760,35 @@ _rtld_unload_object(Obj_Entry *root, bool do_fini_funcs)
}
}
+void
+_rtld_ref_dag(Obj_Entry *root)
+{
+ const Needed_Entry *needed;
+
+ assert(root);
+
+ ++root->refcount;
+
+ dbg(("incremented reference on \"%s\" (%d)", root->path,
+ root->refcount));
+ for (needed = root->needed; needed != NULL;
+ needed = needed->next) {
+ if (needed->obj != NULL)
+ _rtld_ref_dag(needed->obj);
+ }
+}
+
static void
_rtld_unref_dag(Obj_Entry *root)
{
assert(root);
assert(root->refcount != 0);
+
--root->refcount;
+ dbg(("decremented reference on \"%s\" (%d)", root->path,
+ root->refcount));
+
if (root->refcount == 0) {
const Needed_Entry *needed;
@@ -815,6 +837,15 @@ dlopen(const char *name, int mode)
{
Obj_Entry **old_obj_tail = _rtld_objtail;
Obj_Entry *obj = NULL;
+ int flags = _RTLD_DLOPEN;
+ bool nodelete;
+ bool now;
+
+ flags |= (mode & RTLD_GLOBAL) ? _RTLD_GLOBAL : 0;
+ flags |= (mode & RTLD_NOLOAD) ? _RTLD_NOLOAD : 0;
+
+ nodelete = (mode & RTLD_NODELETE) ? true : false;
+ now = ((mode & RTLD_MODEMASK) == RTLD_NOW) ? true : false;
_rtld_debug.r_state = RT_ADD;
_rtld_debug_state();
@@ -823,17 +854,18 @@ dlopen(const char *name, int mode)
obj = _rtld_objmain;
obj->refcount++;
} else
- obj = _rtld_load_library(name, _rtld_objmain, mode);
+ obj = _rtld_load_library(name, _rtld_objmain, flags);
+
if (obj != NULL) {
++obj->dl_refcount;
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
- if (_rtld_load_needed_objects(obj, mode) == -1 ||
+ if (_rtld_load_needed_objects(obj, flags) == -1 ||
(_rtld_init_dag(obj),
_rtld_relocate_objects(obj,
- ((mode & 3) == RTLD_NOW))) == -1) {
+ (now || obj->z_now))) == -1) {
_rtld_unload_object(obj, false);
obj->dl_refcount--;
obj = NULL;
@@ -841,6 +873,13 @@ dlopen(const char *name, int mode)
_rtld_call_init_functions();
}
}
+ if (obj != NULL) {
+ if ((nodelete || obj->z_nodelete) && !obj->ref_nodel) {
+ dbg(("dlopen obj %s nodelete", obj->path));
+ _rtld_ref_dag(obj);
+ obj->z_nodelete = obj->ref_nodel = true;
+ }
+ }
}
_rtld_debug.r_state = RT_CONSISTENT;
_rtld_debug_state();
diff --git a/libexec/ld.elf_so/rtld.h b/libexec/ld.elf_so/rtld.h
index cba3b1739d7..f16626fcd0e 100644
--- a/libexec/ld.elf_so/rtld.h
+++ b/libexec/ld.elf_so/rtld.h
@@ -1,4 +1,4 @@
-/* $NetBSD: rtld.h,v 1.96 2010/12/05 00:56:06 joerg Exp $ */
+/* $NetBSD: rtld.h,v 1.97 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 John D. Polstra.
@@ -128,7 +128,6 @@ typedef struct _rtld_library_xform_t {
#define RTLD_MAGIC 0xd550b87a
#define RTLD_VERSION 1
-#define RTLD_MAIN 0x800
typedef struct Struct_Obj_Entry {
Elf32_Word magic; /* Magic number (sanity check) */
@@ -202,10 +201,17 @@ typedef struct Struct_Obj_Entry {
* called */
fini_called:1, /* True if .fini function has been
* called */
- initfirst:1, /* True if object's .init/.fini take
+ z_now:1, /* True if object's symbols should be
+ bound immediately */
+ z_nodelete:1, /* True if object should never be
+ unloaded */
+ z_initfirst:1, /* True if object's .init/.fini take
* priority over others */
- phdr_loaded:1; /* Phdr is loaded and doesn't need to
+ z_noopen:1, /* True if object should never be
+ dlopen'ed */
+ phdr_loaded:1, /* Phdr is loaded and doesn't need to
* be freed. */
+ ref_nodel:1; /* Refcount increased to prevent dlclose */
struct link_map linkmap; /* for GDB */
@@ -251,6 +257,14 @@ extern Objlist _rtld_list_global;
extern Objlist _rtld_list_main;
extern Elf_Sym _rtld_sym_zero;
+#define RTLD_MODEMASK 0x3
+
+/* Flags for _rtld_load_object() and friends. */
+#define _RTLD_GLOBAL 0x01 /* Add object to global DAG. */
+#define _RTLD_MAIN 0x02
+#define _RTLD_NOLOAD 0x04 /* dlopen() specified RTLD_NOLOAD. */
+#define _RTLD_DLOPEN 0x08 /* Load_object() called from dlopen(). */
+
/* rtld.c */
/* We export these symbols using _rtld_symbol_lookup and is_exported. */
@@ -274,6 +288,7 @@ void _rtld_linkmap_delete(Obj_Entry *);
void _rtld_objlist_push_head(Objlist *, Obj_Entry *);
void _rtld_objlist_push_tail(Objlist *, Obj_Entry *);
Objlist_Entry *_rtld_objlist_find(Objlist *, const Obj_Entry *);
+void _rtld_ref_dag(Obj_Entry *);
/* expand.c */
size_t _rtld_expand_path(char *, size_t, const char *, const char *,\
@@ -288,6 +303,7 @@ Obj_Entry *_rtld_load_object(const char *, int);
int _rtld_load_needed_objects(Obj_Entry *, int);
int _rtld_preload(const char *);
+#define OBJ_ERR (Obj_Entry *)(-1)
/* path.c */
void _rtld_add_paths(const char *, Search_Path **, const char *);
void _rtld_process_hints(const char *, Search_Path **, Library_Xform **,
diff --git a/libexec/ld.elf_so/search.c b/libexec/ld.elf_so/search.c
index 682dc7827c3..513f0adb933 100644
--- a/libexec/ld.elf_so/search.c
+++ b/libexec/ld.elf_so/search.c
@@ -1,4 +1,4 @@
-/* $NetBSD: search.c,v 1.22 2010/08/07 19:47:34 joerg Exp $ */
+/* $NetBSD: search.c,v 1.23 2010/12/24 12:41:43 skrll Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: search.c,v 1.22 2010/08/07 19:47:34 joerg Exp $");
+__RCSID("$NetBSD: search.c,v 1.23 2010/12/24 12:41:43 skrll Exp $");
#endif /* not lint */
#include <err.h>
@@ -67,7 +67,7 @@ static Obj_Entry *_rtld_search_library_path(const char *, size_t,
static Obj_Entry *
_rtld_search_library_path(const char *name, size_t namelen,
- const char *dir, size_t dirlen, int mode)
+ const char *dir, size_t dirlen, int flags)
{
char pathname[MAXPATHLEN];
size_t pathnamelen;
@@ -93,7 +93,7 @@ _rtld_search_library_path(const char *name, size_t namelen,
pathname[pathnamelen] = '\0';
dbg((" Trying \"%s\"", pathname));
- obj = _rtld_load_object(pathname, mode);
+ obj = _rtld_load_object(pathname, flags);
if (obj == NULL) {
Search_Path *path;
@@ -115,7 +115,7 @@ _rtld_search_library_path(const char *name, size_t namelen,
* loaded shared object, whose library search path will be searched.
*/
Obj_Entry *
-_rtld_load_library(const char *name, const Obj_Entry *refobj, int mode)
+_rtld_load_library(const char *name, const Obj_Entry *refobj, int flags)
{
char tmperror[512], *tmperrorp;
Search_Path *sp;
@@ -145,18 +145,18 @@ _rtld_load_library(const char *name, const Obj_Entry *refobj, int mode)
for (sp = _rtld_paths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name, namelen,
- sp->sp_path, sp->sp_pathlen, mode)) != NULL)
+ sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
if (refobj != NULL)
for (sp = refobj->rpaths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name,
- namelen, sp->sp_path, sp->sp_pathlen, mode)) != NULL)
+ namelen, sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
for (sp = _rtld_default_paths; sp != NULL; sp = sp->sp_next)
if ((obj = _rtld_search_library_path(name, namelen,
- sp->sp_path, sp->sp_pathlen, mode)) != NULL)
+ sp->sp_path, sp->sp_pathlen, flags)) != NULL)
goto pathfound;
_rtld_error("Shared object \"%s\" not found", name);
@@ -164,6 +164,12 @@ _rtld_load_library(const char *name, const Obj_Entry *refobj, int mode)
pathfound:
/*
+ * The library has been found, but it couldn't be loaded for some
+ * reason.
+ */
+ if (obj == OBJ_ERR)
+ return NULL;
+ /*
* Successfully found a library; restore the dlerror state as it was
* before _rtld_load_library() was called (any failed call to
* _rtld_search_library_path() will set the dlerror state, but if the
@@ -177,5 +183,10 @@ pathfound:
return obj;
found:
- return _rtld_load_object(pathname, mode);
+ obj = _rtld_load_object(pathname, flags);
+ if (obj == OBJ_ERR)
+ return NULL;
+
+ return obj;
}
+