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