Implement dlopenat(3).

MFC after:	3 weeks
This commit is contained in:
Dag-Erling Smørgrav 2019-01-16 12:12:40 +00:00
parent 8733962697
commit 9b35e90238
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343093
3 changed files with 50 additions and 19 deletions

View File

@ -120,6 +120,7 @@ void *dlopen(const char *, int);
void *dlsym(void * __restrict, const char * __restrict);
#if __BSD_VISIBLE
void *dlopenat(int, const char *, int);
void *fdlopen(int, int);
int dladdr(const void * __restrict, Dl_info * __restrict);
dlfunc_t dlfunc(void * __restrict, const char * __restrict);

View File

@ -32,11 +32,12 @@
.\" @(#) dlopen.3 1.6 90/01/31 SMI
.\" $FreeBSD$
.\"
.Dd January 2, 2019
.Dd January 15, 2019
.Dt DLOPEN 3
.Os
.Sh NAME
.Nm dlopen ,
.Nm dlopenat ,
.Nm fdlopen ,
.Nm dlsym ,
.Nm dlvsym ,
@ -51,6 +52,8 @@
.Ft void *
.Fn dlopen "const char *path" "int mode"
.Ft void *
.Fn dlopenat "int fd" "const char *path" "int mode"
.Ft void *
.Fn fdlopen "int fd" "int mode"
.Ft void *
.Fn dlsym "void * restrict handle" "const char * restrict symbol"
@ -171,6 +174,24 @@ be interrogated with
.Fn dlerror .
.Pp
The
.Fn dlopenat
function is equivalent to
.Fn dlopen
except in the case where the path specifies a relative path.
In this case the file to be opened is determined relative to the
directory associated with the file descriptor fd instead of the
current working directory.
If
.Fn dlopenat
is passed the special value
.Dv AT_FDCWD
in the
.Fa fd
parameter, the current working directory is used and the behavior is
identical to a call to
.Fn dlopen .
.Pp
The
.Fn fdlopen
function is similar to
.Fn dlopen ,

View File

@ -93,8 +93,8 @@ static void digest_dynamic(Obj_Entry *, int);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
static Obj_Entry *dlcheck(void *);
static int dlclose_locked(void *, RtldLockState *);
static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj,
int lo_flags, int mode, RtldLockState *lockstate);
static Obj_Entry *dlopen_object(int, const char *name, int fd,
Obj_Entry *refobj, int lo_flags, int mode, RtldLockState *lockstate);
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 bool donelist_check(DoneList *, const Obj_Entry *);
@ -118,7 +118,7 @@ static void load_filtees(Obj_Entry *, int flags, RtldLockState *);
static void unload_filtees(Obj_Entry *, RtldLockState *);
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 Obj_Entry *load_object(int, const char *, int, const Obj_Entry *, int);
static void map_stacks_exec(RtldLockState *);
static int obj_disable_relro(Obj_Entry *);
static int obj_enforce_relro(Obj_Entry *);
@ -147,7 +147,7 @@ static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, int,
static int resolve_object_ifunc(Obj_Entry *, bool, int, RtldLockState *);
static int rtld_dirname(const char *, char *);
static int rtld_dirname_abs(const char *, char *);
static void *rtld_dlopen(const char *name, int fd, int mode);
static void *rtld_dlopen(int, const char *name, int fd, int mode);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *, const char *,
int *);
@ -231,6 +231,7 @@ extern Elf_Dyn _DYNAMIC;
int dlclose(void *) __exported;
char *dlerror(void) __exported;
void *dlopen(const char *, int) __exported;
void *dlopenat(int, const char *, int) __exported;
void *fdlopen(int, int) __exported;
void *dlsym(void *, const char *) __exported;
dlfunc_t dlfunc(void *, const char *) __exported;
@ -2292,8 +2293,8 @@ load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags,
{
for (; needed != NULL; needed = needed->next) {
needed->obj = dlopen_object(obj->strtab + needed->name, -1, obj,
flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) |
needed->obj = dlopen_object(AT_FDCWD, obj->strtab + needed->name, -1,
obj, flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) |
RTLD_LOCAL, lockstate);
}
}
@ -2316,8 +2317,8 @@ process_needed(Obj_Entry *obj, Needed_Entry *needed, int flags)
Obj_Entry *obj1;
for (; needed != NULL; needed = needed->next) {
obj1 = needed->obj = load_object(obj->strtab + needed->name, -1, obj,
flags & ~RTLD_LO_NOLOAD);
obj1 = needed->obj = load_object(AT_FDCWD, obj->strtab + needed->name,
-1, obj, flags & ~RTLD_LO_NOLOAD);
if (obj1 == NULL && !ld_tracing && (flags & RTLD_LO_FILTEES) == 0)
return (-1);
}
@ -2360,7 +2361,7 @@ load_preload_objects(void)
savech = p[len];
p[len] = '\0';
obj = load_object(p, -1, NULL, 0);
obj = load_object(AT_FDCWD, p, -1, NULL, 0);
if (obj == NULL)
return -1; /* XXX - cleanup */
obj->z_interpose = true;
@ -2389,7 +2390,8 @@ printable_path(const char *path)
* on failure.
*/
static Obj_Entry *
load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags)
load_object(int atfd, const char *name, int fd_u, const Obj_Entry *refobj,
int flags)
{
Obj_Entry *obj;
int fd;
@ -2426,7 +2428,7 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags)
* To avoid a race, we open the file and use fstat() rather than
* using stat().
*/
if ((fd = open(path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) {
if ((fd = openat(atfd, path, O_RDONLY | O_CLOEXEC | O_VERIFY)) == -1) {
_rtld_error("Cannot open \"%s\"", path);
free(path);
return (NULL);
@ -3254,22 +3256,29 @@ dllockinit(void *context,
cur_context_destroy = context_destroy;
}
void *
dlopenat(int fd, const char *name, int mode)
{
return (rtld_dlopen(fd, name, -1, mode));
}
void *
dlopen(const char *name, int mode)
{
return (rtld_dlopen(name, -1, mode));
return (rtld_dlopen(AT_FDCWD, name, -1, mode));
}
void *
fdlopen(int fd, int mode)
{
return (rtld_dlopen(NULL, fd, mode));
return (rtld_dlopen(AT_FDCWD, NULL, fd, mode));
}
static void *
rtld_dlopen(const char *name, int fd, int mode)
rtld_dlopen(int atfd, const char *name, int fd, int mode)
{
RtldLockState lockstate;
int lo_flags;
@ -3291,7 +3300,7 @@ rtld_dlopen(const char *name, int fd, int mode)
if (ld_tracing != NULL)
lo_flags |= RTLD_LO_TRACE;
return (dlopen_object(name, fd, obj_main, lo_flags,
return (dlopen_object(atfd, name, fd, obj_main, lo_flags,
mode & (RTLD_MODEMASK | RTLD_GLOBAL), NULL));
}
@ -3306,8 +3315,8 @@ dlopen_cleanup(Obj_Entry *obj, RtldLockState *lockstate)
}
static Obj_Entry *
dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
int mode, RtldLockState *lockstate)
dlopen_object(int atfd, const char *name, int fd, Obj_Entry *refobj,
int lo_flags, int mode, RtldLockState *lockstate)
{
Obj_Entry *old_obj_tail;
Obj_Entry *obj;
@ -3329,7 +3338,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
obj = obj_main;
obj->refcount++;
} else {
obj = load_object(name, fd, refobj, lo_flags);
obj = load_object(atfd, name, fd, refobj, lo_flags);
}
if (obj) {