rtld direct exec: add -d option

to ignore lack of execute permission on the binary.  The check is a
bad security theatre anyway.

Reviewed by:	arichardson, imp
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D32464
This commit is contained in:
Konstantin Belousov 2021-10-12 01:26:54 +03:00
parent b82168e657
commit ba7f9c1b61
2 changed files with 18 additions and 6 deletions

View File

@ -330,6 +330,7 @@ The syntax of the direct invocation is
.Bd -ragged -offset indent .Bd -ragged -offset indent
.Pa /libexec/ld-elf.so.1 .Pa /libexec/ld-elf.so.1
.Op Fl b Ar exe .Op Fl b Ar exe
.Op Fl d
.Op Fl f Ar fd .Op Fl f Ar fd
.Op Fl p .Op Fl p
.Op Fl u .Op Fl u
@ -352,6 +353,8 @@ If this option is specified,
is only used to provide the is only used to provide the
.Va argv[0] .Va argv[0]
value to the program. value to the program.
.It Fl d
Turn off the emulation of the binary execute permission.
.It Fl f Ar fd .It Fl f Ar fd
File descriptor File descriptor
.Ar fd .Ar fd
@ -403,6 +406,9 @@ ignores
and is naturally prone to race conditions. and is naturally prone to race conditions.
Environments which rely on such restrictions are weak Environments which rely on such restrictions are weak
and breakable on their own. and breakable on their own.
It can be turned off with the
.Fl d
option.
.Sh VERSIONING .Sh VERSIONING
Newer Newer
.Nm .Nm

View File

@ -140,7 +140,7 @@ static void objlist_remove(Objlist *, Obj_Entry *);
static int open_binary_fd(const char *argv0, bool search_in_path, static int open_binary_fd(const char *argv0, bool search_in_path,
const char **binpath_res); const char **binpath_res);
static int parse_args(char* argv[], int argc, bool *use_pathp, int *fdp, static int parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
const char **argv0); const char **argv0, bool *dir_ignore);
static int parse_integer(const char *); static int parse_integer(const char *);
static void *path_enumerate(const char *, path_enum_proc, const char *, void *); static void *path_enumerate(const char *, path_enum_proc, const char *, void *);
static void print_usage(const char *argv0); static void print_usage(const char *argv0);
@ -503,7 +503,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
#ifdef __powerpc__ #ifdef __powerpc__
int old_auxv_format = 1; int old_auxv_format = 1;
#endif #endif
bool dir_enable, direct_exec, explicit_fd, search_in_path; bool dir_enable, dir_ignore, direct_exec, explicit_fd, search_in_path;
/* /*
* On entry, the dynamic linker itself has not been relocated yet. * On entry, the dynamic linker itself has not been relocated yet.
@ -589,7 +589,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
dbg("opening main program in direct exec mode"); dbg("opening main program in direct exec mode");
if (argc >= 2) { if (argc >= 2) {
rtld_argc = parse_args(argv, argc, &search_in_path, &fd, &argv0); rtld_argc = parse_args(argv, argc, &search_in_path, &fd,
&argv0, &dir_ignore);
explicit_fd = (fd != -1); explicit_fd = (fd != -1);
binpath = NULL; binpath = NULL;
if (!explicit_fd) if (!explicit_fd)
@ -621,7 +622,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
} else if ((st.st_mode & S_IXOTH) != 0) { } else if ((st.st_mode & S_IXOTH) != 0) {
dir_enable = true; dir_enable = true;
} }
if (!dir_enable) { if (!dir_enable && !dir_ignore) {
_rtld_error("No execute permission for binary %s", _rtld_error("No execute permission for binary %s",
argv0); argv0);
rtld_die(); rtld_die();
@ -5842,7 +5843,7 @@ open_binary_fd(const char *argv0, bool search_in_path,
*/ */
static int static int
parse_args(char* argv[], int argc, bool *use_pathp, int *fdp, parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
const char **argv0) const char **argv0, bool *dir_ignore)
{ {
const char *arg; const char *arg;
char machine[64]; char machine[64];
@ -5854,6 +5855,7 @@ parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
dbg("Parsing command-line arguments"); dbg("Parsing command-line arguments");
*use_pathp = false; *use_pathp = false;
*fdp = -1; *fdp = -1;
*dir_ignore = false;
seen_b = seen_f = false; seen_b = seen_f = false;
for (i = 1; i < argc; i++ ) { for (i = 1; i < argc; i++ ) {
@ -5890,6 +5892,9 @@ parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
*argv0 = argv[i]; *argv0 = argv[i];
seen_b = true; seen_b = true;
break; break;
} else if (opt == 'd') {
*dir_ignore = true;
break;
} else if (opt == 'f') { } else if (opt == 'f') {
if (seen_b) { if (seen_b) {
_rtld_error("Both -b and -f specified"); _rtld_error("Both -b and -f specified");
@ -5988,11 +5993,12 @@ print_usage(const char *argv0)
{ {
rtld_printf( rtld_printf(
"Usage: %s [-h] [-b <exe>] [-f <FD>] [-p] [--] <binary> [<args>]\n" "Usage: %s [-h] [-b <exe>] [-d] [-f <FD>] [-p] [--] <binary> [<args>]\n"
"\n" "\n"
"Options:\n" "Options:\n"
" -h Display this help message\n" " -h Display this help message\n"
" -b <exe> Execute <exe> instead of <binary>, arg0 is <binary>\n" " -b <exe> Execute <exe> instead of <binary>, arg0 is <binary>\n"
" -d Ignore lack of exec permissions for the binary\n"
" -f <FD> Execute <FD> instead of searching for <binary>\n" " -f <FD> Execute <FD> instead of searching for <binary>\n"
" -p Search in PATH for named binary\n" " -p Search in PATH for named binary\n"
" -u Ignore LD_ environment variables\n" " -u Ignore LD_ environment variables\n"