ld.so: command argument "--preload"

Message ID 8816b7fc-d798-42ee-de51-d1de56e6887c@davidnewall.com
State New, archived
Headers

Commit Message

David Newall Nov. 7, 2018, 7:37 a.m. UTC
  On 6/11/18 11:14 pm, Florian Weimer wrote:
> Don't forget to verify that the test works even if you configure glibc
> with --enable-hardcoded-path-in-tests.  If not, we can disable the test
> in this case.

I've done all that.

Here's a patch that adds --preload to rtld, and  includes a test that 
works with or without --enable-hardcoded-path-in-tests.

By the way, is this a list which permits MIME attachments?

----8<--------8<--------8<--------8<--------8<--------8<--------8<--------8<--
  

Comments

Florian Weimer Nov. 7, 2018, 10:23 a.m. UTC | #1
* David Newall:

> On 6/11/18 11:14 pm, Florian Weimer wrote:
>> Don't forget to verify that the test works even if you configure glibc
>> with --enable-hardcoded-path-in-tests.  If not, we can disable the test
>> in this case.
>
> I've done all that.
>
> Here's a patch that adds --preload to rtld, and  includes a test that
> works with or without --enable-hardcoded-path-in-tests.
>
> By the way, is this a list which permits MIME attachments?

Yes, as long as it's not text/html.  Please resend your patch as an
attachment; it looks like some lines were wrapped.

Thanks,
Florian
  

Patch

diff --git a/elf/Makefile b/elf/Makefile
index d72e7b6..901e188 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -353,7 +353,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
@@ -882,6 +883,13 @@  $(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
+	$(SHELL) $^ '$(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 1b0c747..f046f6e 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -826,6 +826,8 @@  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
@@ -833,8 +835,9 @@  static int version_info attribute_relro;
     (If the binary is running setuid all elements containing a '/' are
     ignored since it is insecure.)  Return the number of preloads
     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;
  }
@@ -978,6 +981,13 @@  dl_main (const ElfW(Phdr) *phdr,
  	    _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;
+	  }
  	else
  	  break;
  
@@ -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 0000000..4a6a58d
--- /dev/null
+++ b/elf/tst-rtld-preload.sh
@@ -0,0 +1,37 @@ 
+#!/bin/sh
+# Test how rtld loads itself.
+# Copyright (C) 2012-2016 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
+#. + +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