d8307d
commit 8692ebdb1259be60c545fa509d4852b26703777e
d8307d
Author: David Newall <glibc@davidnewall.com>
d8307d
Date:   Mon Feb 4 13:35:11 2019 +0100
d8307d
d8307d
    elf: Implement --preload option for the dynamic linker
d8307d
d8307d
diff --git a/elf/Makefile b/elf/Makefile
d8307d
index 9cf5cd8dfd..db6a2a0c29 100644
d8307d
--- a/elf/Makefile
d8307d
+++ b/elf/Makefile
d8307d
@@ -354,7 +354,8 @@ endif
d8307d
 
d8307d
 ifeq (yes,$(build-shared))
d8307d
 ifeq ($(run-built-tests),yes)
d8307d
-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
d8307d
+tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \
d8307d
+		 $(objpfx)tst-rtld-preload.out
d8307d
 endif
d8307d
 tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \
d8307d
 		 $(objpfx)check-localplt.out $(objpfx)check-initfini.out
d8307d
@@ -883,6 +884,15 @@ $(objpfx)tst-rtld-load-self.out: tst-rtld-load-self.sh $(objpfx)ld.so
d8307d
 	$(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' > $@; \
d8307d
 	$(evaluate-test)
d8307d
 
d8307d
+tst-rtld-preload-OBJS = $(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
d8307d
+$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \
d8307d
+			       $(objpfx)preloadtest \
d8307d
+			       $(preloadtest-preloads:%=$(objpfx)%.so)
d8307d
+	$(SHELL) $< $(objpfx)ld.so $(objpfx)preloadtest \
d8307d
+		    '$(test-wrapper)' '$(test-wrapper-env)' '$(run_program_env)' \
d8307d
+		    '$(rpath-link)' '$(tst-rtld-preload-OBJS)' > $@; \
d8307d
+	$(evaluate-test)
d8307d
+
d8307d
 $(objpfx)initfirst: $(libdl)
d8307d
 $(objpfx)initfirst.out: $(objpfx)firstobj.so
d8307d
 
d8307d
diff --git a/elf/rtld.c b/elf/rtld.c
d8307d
index 5d97f41b7b..5a90e78ed6 100644
d8307d
--- a/elf/rtld.c
d8307d
+++ b/elf/rtld.c
d8307d
@@ -826,15 +826,18 @@ static const char *library_path attribute_relro;
d8307d
 static const char *preloadlist attribute_relro;
d8307d
 /* Nonzero if information about versions has to be printed.  */
d8307d
 static int version_info attribute_relro;
d8307d
+/* The preload list passed as a command argument.  */
d8307d
+static const char *preloadarg attribute_relro;
d8307d
 
d8307d
 /* The LD_PRELOAD environment variable gives list of libraries
d8307d
    separated by white space or colons that are loaded before the
d8307d
    executable's dependencies and prepended to the global scope list.
d8307d
    (If the binary is running setuid all elements containing a '/' are
d8307d
    ignored since it is insecure.)  Return the number of preloads
d8307d
-   performed.  */
d8307d
+   performed.   Ditto for --preload command argument.  */
d8307d
 unsigned int
d8307d
-handle_ld_preload (const char *preloadlist, struct link_map *main_map)
d8307d
+handle_preload_list (const char *preloadlist, struct link_map *main_map,
d8307d
+		     const char *where)
d8307d
 {
d8307d
   unsigned int npreloads = 0;
d8307d
   const char *p = preloadlist;
d8307d
@@ -858,7 +861,7 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map)
d8307d
 	++p;
d8307d
 
d8307d
       if (dso_name_valid_for_suid (fname))
d8307d
-	npreloads += do_preload (fname, main_map, "LD_PRELOAD");
d8307d
+	npreloads += do_preload (fname, main_map, where);
d8307d
     }
d8307d
   return npreloads;
d8307d
 }
d8307d
@@ -974,6 +977,13 @@ dl_main (const ElfW(Phdr) *phdr,
d8307d
 	  {
d8307d
 	    process_dl_audit (_dl_argv[2]);
d8307d
 
d8307d
+	    _dl_skip_args += 2;
d8307d
+	    _dl_argc -= 2;
d8307d
+	    _dl_argv += 2;
d8307d
+	  }
d8307d
+	else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
d8307d
+	  {
d8307d
+	    preloadarg = _dl_argv[2];
d8307d
 	    _dl_skip_args += 2;
d8307d
 	    _dl_argc -= 2;
d8307d
 	    _dl_argv += 2;
d8307d
@@ -1006,7 +1016,8 @@ of this helper program; chances are you did not intend to run this program.\n\
d8307d
 			variable LD_LIBRARY_PATH\n\
d8307d
   --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names\n\
d8307d
 			in LIST\n\
d8307d
-  --audit LIST          use objects named in LIST as auditors\n");
d8307d
+  --audit LIST          use objects named in LIST as auditors\n\
d8307d
+  --preload LIST        preload objects named in LIST\n");
d8307d
 
d8307d
       ++_dl_skip_args;
d8307d
       --_dl_argc;
d8307d
@@ -1620,7 +1631,16 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
d8307d
   if (__glibc_unlikely (preloadlist != NULL))
d8307d
     {
d8307d
       HP_TIMING_NOW (start);
d8307d
-      npreloads += handle_ld_preload (preloadlist, main_map);
d8307d
+      npreloads += handle_preload_list (preloadlist, main_map, "LD_PRELOAD");
d8307d
+      HP_TIMING_NOW (stop);
d8307d
+      HP_TIMING_DIFF (diff, start, stop);
d8307d
+      HP_TIMING_ACCUM_NT (load_time, diff);
d8307d
+    }
d8307d
+
d8307d
+  if (__glibc_unlikely (preloadarg != NULL))
d8307d
+    {
d8307d
+      HP_TIMING_NOW (start);
d8307d
+      npreloads += handle_preload_list (preloadarg, main_map, "--preload");
d8307d
       HP_TIMING_NOW (stop);
d8307d
       HP_TIMING_DIFF (diff, start, stop);
d8307d
       HP_TIMING_ACCUM_NT (load_time, diff);
d8307d
diff --git a/elf/tst-rtld-preload.sh b/elf/tst-rtld-preload.sh
d8307d
new file mode 100755
d8307d
index 0000000000..f0c0ca11ba
d8307d
--- /dev/null
d8307d
+++ b/elf/tst-rtld-preload.sh
d8307d
@@ -0,0 +1,38 @@
d8307d
+#!/bin/sh
d8307d
+# Test --preload argument ld.so.
d8307d
+# Copyright (C) 2019 Free Software Foundation, Inc.
d8307d
+# This file is part of the GNU C Library.
d8307d
+#
d8307d
+# The GNU C Library is free software; you can redistribute it and/or
d8307d
+# modify it under the terms of the GNU Lesser General Public
d8307d
+# License as published by the Free Software Foundation; either
d8307d
+# version 2.1 of the License, or (at your option) any later version.
d8307d
+#
d8307d
+# The GNU C Library is distributed in the hope that it will be useful,
d8307d
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
d8307d
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d8307d
+# Lesser General Public License for more details.
d8307d
+#
d8307d
+# You should have received a copy of the GNU Lesser General Public
d8307d
+# License along with the GNU C Library; if not, see
d8307d
+# <http://www.gnu.org/licenses/>.
d8307d
+
d8307d
+set -e
d8307d
+
d8307d
+rtld=$1
d8307d
+test_program=$2
d8307d
+test_wrapper=$3
d8307d
+test_wrapper_env=$4
d8307d
+run_program_env=$5
d8307d
+library_path=$6
d8307d
+preload=$7
d8307d
+
d8307d
+echo "# [${test_wrapper}] [$rtld] [--library-path] [$library_path]" \
d8307d
+     "[--preload] [$preload] [$test_program]"
d8307d
+${test_wrapper_env} \
d8307d
+${run_program_env} \
d8307d
+${test_wrapper} $rtld --library-path "$library_path" \
d8307d
+  --preload "$preload" $test_program 2>&1 && rc=0 || rc=$?
d8307d
+echo "# exit status $rc"
d8307d
+
d8307d
+exit $rc