Implement rtld part of the support for -z nodlopen (see ld(1)).
Reviewed by: kan MFC after: 3 weeks
This commit is contained in:
parent
0dba9623fa
commit
8f8a9dcd17
@ -87,7 +87,7 @@ static void die(void) __dead2;
|
|||||||
static void digest_dynamic(Obj_Entry *, int);
|
static void digest_dynamic(Obj_Entry *, int);
|
||||||
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
|
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
|
||||||
static Obj_Entry *dlcheck(void *);
|
static Obj_Entry *dlcheck(void *);
|
||||||
static Obj_Entry *do_load_object(int, const char *, char *, struct stat *);
|
static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int);
|
||||||
static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
|
static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
|
||||||
static bool donelist_check(DoneList *, const Obj_Entry *);
|
static bool donelist_check(DoneList *, const Obj_Entry *);
|
||||||
static void errmsg_restore(char *);
|
static void errmsg_restore(char *);
|
||||||
@ -103,7 +103,7 @@ static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
|
|||||||
static bool is_exported(const Elf_Sym *);
|
static bool is_exported(const Elf_Sym *);
|
||||||
static void linkmap_add(Obj_Entry *);
|
static void linkmap_add(Obj_Entry *);
|
||||||
static void linkmap_delete(Obj_Entry *);
|
static void linkmap_delete(Obj_Entry *);
|
||||||
static int load_needed_objects(Obj_Entry *);
|
static int load_needed_objects(Obj_Entry *, int);
|
||||||
static int load_preload_objects(void);
|
static int load_preload_objects(void);
|
||||||
static Obj_Entry *load_object(const char *, const Obj_Entry *, int);
|
static Obj_Entry *load_object(const char *, const Obj_Entry *, int);
|
||||||
static Obj_Entry *obj_from_addr(const void *);
|
static Obj_Entry *obj_from_addr(const void *);
|
||||||
@ -485,7 +485,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
|||||||
preload_tail = obj_tail;
|
preload_tail = obj_tail;
|
||||||
|
|
||||||
dbg("loading needed objects");
|
dbg("loading needed objects");
|
||||||
if (load_needed_objects(obj_main) == -1)
|
if (load_needed_objects(obj_main, 0) == -1)
|
||||||
die();
|
die();
|
||||||
|
|
||||||
/* Make a list of all objects loaded at startup. */
|
/* Make a list of all objects loaded at startup. */
|
||||||
@ -932,6 +932,8 @@ digest_dynamic(Obj_Entry *obj, int early)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case DT_FLAGS_1:
|
case DT_FLAGS_1:
|
||||||
|
if (dynp->d_un.d_val & DF_1_NOOPEN)
|
||||||
|
obj->z_noopen = true;
|
||||||
if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
|
if ((dynp->d_un.d_val & DF_1_ORIGIN) && trust)
|
||||||
obj->z_origin = true;
|
obj->z_origin = true;
|
||||||
if (dynp->d_un.d_val & DF_1_GLOBAL)
|
if (dynp->d_un.d_val & DF_1_GLOBAL)
|
||||||
@ -1425,7 +1427,7 @@ is_exported(const Elf_Sym *def)
|
|||||||
* returns -1 on failure.
|
* returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
load_needed_objects(Obj_Entry *first)
|
load_needed_objects(Obj_Entry *first, int flags)
|
||||||
{
|
{
|
||||||
Obj_Entry *obj, *obj1;
|
Obj_Entry *obj, *obj1;
|
||||||
|
|
||||||
@ -1434,7 +1436,7 @@ load_needed_objects(Obj_Entry *first)
|
|||||||
|
|
||||||
for (needed = obj->needed; needed != NULL; needed = needed->next) {
|
for (needed = obj->needed; needed != NULL; needed = needed->next) {
|
||||||
obj1 = needed->obj = load_object(obj->strtab + needed->name, obj,
|
obj1 = needed->obj = load_object(obj->strtab + needed->name, obj,
|
||||||
false);
|
flags & ~RTLD_LO_NOLOAD);
|
||||||
if (obj1 == NULL && !ld_tracing)
|
if (obj1 == NULL && !ld_tracing)
|
||||||
return -1;
|
return -1;
|
||||||
if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) {
|
if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) {
|
||||||
@ -1465,7 +1467,7 @@ load_preload_objects(void)
|
|||||||
|
|
||||||
savech = p[len];
|
savech = p[len];
|
||||||
p[len] = '\0';
|
p[len] = '\0';
|
||||||
if (load_object(p, NULL, false) == NULL)
|
if (load_object(p, NULL, 0) == NULL)
|
||||||
return -1; /* XXX - cleanup */
|
return -1; /* XXX - cleanup */
|
||||||
p[len] = savech;
|
p[len] = savech;
|
||||||
p += len;
|
p += len;
|
||||||
@ -1482,7 +1484,7 @@ load_preload_objects(void)
|
|||||||
* on failure.
|
* on failure.
|
||||||
*/
|
*/
|
||||||
static Obj_Entry *
|
static Obj_Entry *
|
||||||
load_object(const char *name, const Obj_Entry *refobj, int noload)
|
load_object(const char *name, const Obj_Entry *refobj, int flags)
|
||||||
{
|
{
|
||||||
Obj_Entry *obj;
|
Obj_Entry *obj;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
@ -1528,11 +1530,11 @@ load_object(const char *name, const Obj_Entry *refobj, int noload)
|
|||||||
close(fd);
|
close(fd);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
if (noload)
|
if (flags & RTLD_LO_NOLOAD)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
/* First use of this object, so we must map it in */
|
/* First use of this object, so we must map it in */
|
||||||
obj = do_load_object(fd, name, path, &sb);
|
obj = do_load_object(fd, name, path, &sb, flags);
|
||||||
if (obj == NULL)
|
if (obj == NULL)
|
||||||
free(path);
|
free(path);
|
||||||
close(fd);
|
close(fd);
|
||||||
@ -1541,7 +1543,8 @@ load_object(const char *name, const Obj_Entry *refobj, int noload)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Obj_Entry *
|
static Obj_Entry *
|
||||||
do_load_object(int fd, const char *name, char *path, struct stat *sbp)
|
do_load_object(int fd, const char *name, char *path, struct stat *sbp,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
Obj_Entry *obj;
|
Obj_Entry *obj;
|
||||||
struct statfs fs;
|
struct statfs fs;
|
||||||
@ -1568,6 +1571,13 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp)
|
|||||||
object_add_name(obj, name);
|
object_add_name(obj, name);
|
||||||
obj->path = path;
|
obj->path = path;
|
||||||
digest_dynamic(obj, 0);
|
digest_dynamic(obj, 0);
|
||||||
|
if (obj->z_noopen && (flags & RTLD_LO_DLOPEN)) {
|
||||||
|
dbg("refusing to load non-loadable \"%s\"", obj->path);
|
||||||
|
_rtld_error("Cannot dlopen non-loadable %s\n", obj->path);
|
||||||
|
munmap(obj->mapbase, obj->mapsize);
|
||||||
|
obj_free(obj);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
*obj_tail = obj;
|
*obj_tail = obj;
|
||||||
obj_tail = &obj->next;
|
obj_tail = &obj->next;
|
||||||
@ -1986,14 +1996,16 @@ dlopen(const char *name, int mode)
|
|||||||
Obj_Entry **old_obj_tail;
|
Obj_Entry **old_obj_tail;
|
||||||
Obj_Entry *obj;
|
Obj_Entry *obj;
|
||||||
Objlist initlist;
|
Objlist initlist;
|
||||||
int result, lockstate, nodelete, noload;
|
int result, lockstate, nodelete, lo_flags;
|
||||||
|
|
||||||
LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name);
|
LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name);
|
||||||
ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
|
ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
|
||||||
if (ld_tracing != NULL)
|
if (ld_tracing != NULL)
|
||||||
environ = (char **)*get_program_var_addr("environ");
|
environ = (char **)*get_program_var_addr("environ");
|
||||||
nodelete = mode & RTLD_NODELETE;
|
nodelete = mode & RTLD_NODELETE;
|
||||||
noload = mode & RTLD_NOLOAD;
|
lo_flags = RTLD_LO_DLOPEN;
|
||||||
|
if (mode & RTLD_NOLOAD)
|
||||||
|
lo_flags |= RTLD_LO_NOLOAD;
|
||||||
|
|
||||||
objlist_init(&initlist);
|
objlist_init(&initlist);
|
||||||
|
|
||||||
@ -2006,7 +2018,7 @@ dlopen(const char *name, int mode)
|
|||||||
obj = obj_main;
|
obj = obj_main;
|
||||||
obj->refcount++;
|
obj->refcount++;
|
||||||
} else {
|
} else {
|
||||||
obj = load_object(name, obj_main, noload);
|
obj = load_object(name, obj_main, lo_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
@ -2016,7 +2028,7 @@ dlopen(const char *name, int mode)
|
|||||||
mode &= RTLD_MODEMASK;
|
mode &= RTLD_MODEMASK;
|
||||||
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
if (*old_obj_tail != NULL) { /* We loaded something new. */
|
||||||
assert(*old_obj_tail == obj);
|
assert(*old_obj_tail == obj);
|
||||||
result = load_needed_objects(obj);
|
result = load_needed_objects(obj, RTLD_LO_DLOPEN);
|
||||||
init_dag(obj);
|
init_dag(obj);
|
||||||
if (result != -1)
|
if (result != -1)
|
||||||
result = rtld_verify_versions(&obj->dagmembers);
|
result = rtld_verify_versions(&obj->dagmembers);
|
||||||
|
@ -218,6 +218,7 @@ typedef struct Struct_Obj_Entry {
|
|||||||
bool phdr_alloc : 1; /* Phdr is allocated and needs to be freed. */
|
bool phdr_alloc : 1; /* Phdr is allocated and needs to be freed. */
|
||||||
bool z_origin : 1; /* Process rpath and soname tokens */
|
bool z_origin : 1; /* Process rpath and soname tokens */
|
||||||
bool z_nodelete : 1; /* Do not unload the object and dependencies */
|
bool z_nodelete : 1; /* Do not unload the object and dependencies */
|
||||||
|
bool z_noopen : 1; /* Do not load on dlopen */
|
||||||
bool ref_nodel : 1; /* Refcount increased to prevent dlclose */
|
bool ref_nodel : 1; /* Refcount increased to prevent dlclose */
|
||||||
bool init_scanned: 1; /* Object is already on init list. */
|
bool init_scanned: 1; /* Object is already on init list. */
|
||||||
bool on_fini_list: 1; /* Object is already on fini list. */
|
bool on_fini_list: 1; /* Object is already on fini list. */
|
||||||
@ -240,6 +241,10 @@ typedef struct Struct_Obj_Entry {
|
|||||||
#define SYMLOOK_DLSYM 0x02 /* Return newes versioned symbol. Used by
|
#define SYMLOOK_DLSYM 0x02 /* Return newes versioned symbol. Used by
|
||||||
dlsym. */
|
dlsym. */
|
||||||
|
|
||||||
|
/* Flags for load_object(). */
|
||||||
|
#define RTLD_LO_NOLOAD 0x01 /* dlopen() specified RTLD_NOLOAD */
|
||||||
|
#define RTLD_LO_DLOPEN 0x02 /* load_object() called from dlopen(). */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Symbol cache entry used during relocation to avoid multiple lookups
|
* Symbol cache entry used during relocation to avoid multiple lookups
|
||||||
* of the same symbol.
|
* of the same symbol.
|
||||||
|
@ -471,6 +471,7 @@ typedef struct {
|
|||||||
#define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */
|
#define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */
|
||||||
#define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */
|
#define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */
|
||||||
#define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */
|
#define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */
|
||||||
|
#define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */
|
||||||
#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */
|
#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */
|
||||||
|
|
||||||
/* Values for n_type. Used in core files. */
|
/* Values for n_type. Used in core files. */
|
||||||
|
Loading…
Reference in New Issue
Block a user