diff options
| author | skrll <skrll@NetBSD.org> | 2010-12-24 12:41:42 +0000 |
|---|---|---|
| committer | skrll <skrll@NetBSD.org> | 2010-12-24 12:41:42 +0000 |
| commit | 3cd6f36785365945ee7cc808cdb0d6f5396d4fcf (patch) | |
| tree | 4d32293a7d5147e62a2f594e98b9c3dadaf13225 /libexec | |
| parent | acf15340b17d10b7a16cd58703a258f2bfc8073a (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.c | 12 | ||||
| -rw-r--r-- | libexec/ld.elf_so/load.c | 49 | ||||
| -rw-r--r-- | libexec/ld.elf_so/reloc.c | 6 | ||||
| -rw-r--r-- | libexec/ld.elf_so/rtld.c | 55 | ||||
| -rw-r--r-- | libexec/ld.elf_so/rtld.h | 24 | ||||
| -rw-r--r-- | libexec/ld.elf_so/search.c | 29 |
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; } + |
