Allow rtld direct-exec to take a file descriptor.
When executing rtld directly, allow a file descriptor to be explicitly specified rather than opened from the given path. This, together with the LD_LIBRARY_PATH_FDS environment variable, allows dynamically-linked applications to be executed from within capability mode. Also add some rudimentary argument parsing (without pulling in getopt or the like) to accept this file descriptor, a help (-h) option and a basic usage string. Reviewed by: kib Sponsored by: NSERC, RDC Differential Revision: https://reviews.freebsd.org/D10751
This commit is contained in:
parent
5033c43b7a
commit
d5a5e50d3b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=318431
@ -115,8 +115,10 @@ static void objlist_push_head(Objlist *, Obj_Entry *);
|
||||
static void objlist_push_tail(Objlist *, Obj_Entry *);
|
||||
static void objlist_put_after(Objlist *, Obj_Entry *, Obj_Entry *);
|
||||
static void objlist_remove(Objlist *, Obj_Entry *);
|
||||
static int parse_args(char* argv[], int argc, bool *use_pathp, int *fdp);
|
||||
static int parse_integer(const char *);
|
||||
static void *path_enumerate(const char *, path_enum_proc, void *);
|
||||
static void print_usage(const char *argv0);
|
||||
static void release_object(Obj_Entry *);
|
||||
static int relocate_object_dag(Obj_Entry *root, bool bind_now,
|
||||
Obj_Entry *rtldobj, int flags, RtldLockState *lockstate);
|
||||
@ -350,9 +352,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
||||
char **argv, *argv0, **env, **envp, *kexecpath, *library_path_rpath;
|
||||
caddr_t imgentry;
|
||||
char buf[MAXPATHLEN];
|
||||
int argc, fd, i, mib[2], phnum;
|
||||
int argc, fd, i, mib[2], phnum, rtld_argc;
|
||||
size_t len;
|
||||
bool dir_enable;
|
||||
bool dir_enable, explicit_fd, search_in_path;
|
||||
|
||||
/*
|
||||
* On entry, the dynamic linker itself has not been relocated yet.
|
||||
@ -428,7 +430,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
||||
}
|
||||
dbg("opening main program in direct exec mode");
|
||||
if (argc >= 2) {
|
||||
argv0 = argv[1];
|
||||
rtld_argc = parse_args(argv, argc, &search_in_path, &fd);
|
||||
argv0 = argv[rtld_argc];
|
||||
explicit_fd = (fd != -1);
|
||||
if (!explicit_fd)
|
||||
fd = open(argv0, O_RDONLY | O_CLOEXEC | O_VERIFY);
|
||||
if (fd == -1) {
|
||||
rtld_printf("Opening %s: %s\n", argv0,
|
||||
@ -436,7 +441,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
||||
rtld_die();
|
||||
}
|
||||
if (fstat(fd, &st) == -1) {
|
||||
rtld_printf("Stat %s: %s\n", argv0,
|
||||
_rtld_error("failed to fstat FD %d (%s): %s", fd,
|
||||
explicit_fd ? "user-provided descriptor" : argv0,
|
||||
rtld_strerror(errno));
|
||||
rtld_die();
|
||||
}
|
||||
@ -469,26 +475,23 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
|
||||
|
||||
/*
|
||||
* For direct exec mode, argv[0] is the interpreter
|
||||
* name, we must remove it and shift arguments left by
|
||||
* 1 before invoking binary main. Since stack layout
|
||||
* name, we must remove it and shift arguments left
|
||||
* before invoking binary main. Since stack layout
|
||||
* places environment pointers and aux vectors right
|
||||
* after the terminating NULL, we must shift
|
||||
* environment and aux as well.
|
||||
* XXX Shift will be > 1 when options are implemented.
|
||||
*/
|
||||
main_argc = argc - rtld_argc;
|
||||
for (i = 0; i <= main_argc; i++)
|
||||
argv[i] = argv[i + rtld_argc];
|
||||
*argcp -= rtld_argc;
|
||||
environ = env = envp = argv + main_argc + 1;
|
||||
do {
|
||||
*argv = *(argv + 1);
|
||||
argv++;
|
||||
} while (*argv != NULL);
|
||||
*argcp -= 1;
|
||||
main_argc = argc - 1;
|
||||
environ = env = envp = argv;
|
||||
do {
|
||||
*envp = *(envp + 1);
|
||||
*envp = *(envp + rtld_argc);
|
||||
envp++;
|
||||
} while (*envp != NULL);
|
||||
aux = auxp = (Elf_Auxinfo *)envp;
|
||||
auxpf = (Elf_Auxinfo *)(envp + 1);
|
||||
auxpf = (Elf_Auxinfo *)(envp + rtld_argc);
|
||||
for (;; auxp++, auxpf++) {
|
||||
*auxp = *auxpf;
|
||||
if (auxp->a_type == AT_NULL)
|
||||
@ -5273,6 +5276,81 @@ symlook_init_from_req(SymLook *dst, const SymLook *src)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse a set of command-line arguments.
|
||||
*/
|
||||
static int
|
||||
parse_args(char* argv[], int argc, bool *use_pathp, int *fdp)
|
||||
{
|
||||
const char *arg;
|
||||
int fd, i, j, arglen;
|
||||
char opt;
|
||||
|
||||
dbg("Parsing command-line arguments");
|
||||
*use_pathp = false;
|
||||
*fdp = -1;
|
||||
|
||||
for (i = 1; i < argc; i++ ) {
|
||||
arg = argv[i];
|
||||
dbg("argv[%d]: '%s'", i, arg);
|
||||
|
||||
/*
|
||||
* rtld arguments end with an explicit "--" or with the first
|
||||
* non-prefixed argument.
|
||||
*/
|
||||
if (strcmp(arg, "--") == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
|
||||
/*
|
||||
* All other arguments are single-character options that can
|
||||
* be combined, so we need to search through `arg` for them.
|
||||
*/
|
||||
arglen = strlen(arg);
|
||||
for (j = 1; j < arglen; j++) {
|
||||
opt = arg[j];
|
||||
if (opt == 'h') {
|
||||
print_usage(argv[0]);
|
||||
rtld_die();
|
||||
} else if (opt == 'f') {
|
||||
/*
|
||||
* -f XX can be used to specify a descriptor for the
|
||||
* binary named at the command line (i.e., the later
|
||||
* argument will specify the process name but the
|
||||
* descriptor is what will actually be executed)
|
||||
*/
|
||||
if (j != arglen - 1) {
|
||||
/* -f must be the last option in, e.g., -abcf */
|
||||
_rtld_error("invalid options: %s", arg);
|
||||
rtld_die();
|
||||
}
|
||||
i++;
|
||||
fd = parse_integer(argv[i]);
|
||||
if (fd == -1) {
|
||||
_rtld_error("invalid file descriptor: '%s'",
|
||||
argv[i]);
|
||||
rtld_die();
|
||||
}
|
||||
*fdp = fd;
|
||||
break;
|
||||
/* TODO:
|
||||
} else if (opt == 'p') {
|
||||
*use_pathp = true;
|
||||
*/
|
||||
} else {
|
||||
rtld_printf("invalid argument: '%s'\n", arg);
|
||||
print_usage(argv[0]);
|
||||
rtld_die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a file descriptor number without pulling in more of libc (e.g. atoi).
|
||||
*/
|
||||
@ -5300,6 +5378,20 @@ parse_integer(const char *str)
|
||||
return (n);
|
||||
}
|
||||
|
||||
void print_usage(const char *argv0)
|
||||
{
|
||||
|
||||
rtld_printf("Usage: %s [-h] [-f <FD>] [--] <binary> [<args>]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h Display this help message\n"
|
||||
/* TODO: " -p Search in PATH for named binary\n" */
|
||||
" -f <FD> Execute <FD> instead of searching for <binary>\n"
|
||||
" -- End of RTLD options\n"
|
||||
" <binary> Name of process to execute\n"
|
||||
" <args> Arguments to the executed process\n", argv0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for libc_pic-provided functions.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user