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