git: ba7f9c1b6132 - main - rtld direct exec: add -d option

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 13 Oct 2021 00:42:08 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=ba7f9c1b61329630af25e75cdaca261b389318c7

commit ba7f9c1b61329630af25e75cdaca261b389318c7
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-11 22:26:54 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-13 00:41:48 +0000

    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
---
 libexec/rtld-elf/rtld.1 |  6 ++++++
 libexec/rtld-elf/rtld.c | 18 ++++++++++++------
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1
index 8bc4cfade070..187dc105667a 100644
--- a/libexec/rtld-elf/rtld.1
+++ b/libexec/rtld-elf/rtld.1
@@ -330,6 +330,7 @@ The syntax of the direct invocation is
 .Bd -ragged -offset indent
 .Pa /libexec/ld-elf.so.1
 .Op Fl b Ar exe
+.Op Fl d
 .Op Fl f Ar fd
 .Op Fl p
 .Op Fl u
@@ -352,6 +353,8 @@ If this option is specified,
 is only used to provide the
 .Va argv[0]
 value to the program.
+.It Fl d
+Turn off the emulation of the binary execute permission.
 .It Fl f Ar fd
 File descriptor
 .Ar fd
@@ -403,6 +406,9 @@ ignores
 and is naturally prone to race conditions.
 Environments which rely on such restrictions are weak
 and breakable on their own.
+It can be turned off with the
+.Fl d
+option.
 .Sh VERSIONING
 Newer
 .Nm
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 1a89a7b2c1de..6c304f98253a 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -140,7 +140,7 @@ static void objlist_remove(Objlist *, Obj_Entry *);
 static int open_binary_fd(const char *argv0, bool search_in_path,
     const char **binpath_res);
 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 void *path_enumerate(const char *, path_enum_proc, const char *, void *);
 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__
     int old_auxv_format = 1;
 #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.
@@ -589,7 +589,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 
 	    dbg("opening main program in direct exec mode");
 	    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);
 		binpath = NULL;
 		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) {
 		    dir_enable = true;
 		}
-		if (!dir_enable) {
+		if (!dir_enable && !dir_ignore) {
 		    _rtld_error("No execute permission for binary %s",
 		        argv0);
 		    rtld_die();
@@ -5842,7 +5843,7 @@ open_binary_fd(const char *argv0, bool search_in_path,
  */
 static int
 parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
-    const char **argv0)
+    const char **argv0, bool *dir_ignore)
 {
 	const char *arg;
 	char machine[64];
@@ -5854,6 +5855,7 @@ parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
 	dbg("Parsing command-line arguments");
 	*use_pathp = false;
 	*fdp = -1;
+	*dir_ignore = false;
 	seen_b = seen_f = false;
 
 	for (i = 1; i < argc; i++ ) {
@@ -5890,6 +5892,9 @@ parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
 				*argv0 = argv[i];
 				seen_b = true;
 				break;
+			} else if (opt == 'd') {
+				*dir_ignore = true;
+				break;
 			} else if (opt == 'f') {
 				if (seen_b) {
 					_rtld_error("Both -b and -f specified");
@@ -5988,11 +5993,12 @@ print_usage(const char *argv0)
 {
 
 	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"
 	    "Options:\n"
 	    "  -h        Display this help message\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"
 	    "  -p        Search in PATH for named binary\n"
 	    "  -u        Ignore LD_ environment variables\n"