ld.so: command argument "--preload"

Message ID 43265e8e-956a-f895-6c04-8cd6898a8c97@davidnewall.com
State New, archived
Headers

Commit Message

David Newall Nov. 7, 2018, 12:32 p.m. UTC
  On 7/11/18 8:53 pm, Florian Weimer wrote:
> Yes, as long as it's not text/html.  Please resend your patch as an
> attachment; it looks like some lines were wrapped.

I like HTML email (I know! and I've been doing UNIX since '80s) but this 
client is doing the movement no favour by mangling what I asked to be 
pre-formatted text.  Here it is as an attachment.
  

Comments

Florian Weimer Nov. 7, 2018, 1:32 p.m. UTC | #1
* David Newall:

> On 7/11/18 8:53 pm, Florian Weimer wrote:
>> Yes, as long as it's not text/html.  Please resend your patch as an
>> attachment; it looks like some lines were wrapped.
>
> I like HTML email (I know! and I've been doing UNIX since '80s) but
> this client is doing the movement no favour by mangling what I asked
> to be pre-formatted text.  Here it is as an attachment.

Much better, thanks.

> 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

Missing dependency on the objects in $(tst-rtld-preload-OBJS), I think.
I expect you need to add the prefix $(objpfx) to the dependency.

> +	$(SHELL) $^ '$(test-wrapper)' '$(test-wrapper-env)' '$(run_program_env)' \
> +		    '$(rpath-link)' '$(tst-rtld-preload-OBJS)' > $@; \
> + 	$(evaluate-test)

There are two whitespace errors on this line (leading and trailing
space).

>  $(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 */

I would merge the last line into the existing comment, and there should
be a ".  " at the end (period followed by two spaces, as before).

>  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)

Please wrap the at 79 characters.

Rest looks good to me.

Thanks,
Florian
  
David Newall Nov. 7, 2018, 2:03 p.m. UTC | #2
On 8/11/18 12:02 am, Florian Weimer wrote:
>>   
>> +tst-rtld-preload-OBJS =  $(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
>> +$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \
>> +			       $(objpfx)preloadtest
> Missing dependency on the objects in $(tst-rtld-preload-OBJS), I think.
I think not.  This is the same as preloadtest-ENV (without 
"LD_PRELOAD=").  Is it okay?  Should I have included a comment to 
explain this?
  
Florian Weimer Nov. 7, 2018, 2:06 p.m. UTC | #3
* David Newall:

> On 8/11/18 12:02 am, Florian Weimer wrote:
>>>   +tst-rtld-preload-OBJS =  $(subst $(empty) ,:,$(strip
>>> $(preloadtest-preloads:=.so)))
>>> +$(objpfx)tst-rtld-preload.out: tst-rtld-preload.sh $(objpfx)ld.so \
>>> +			       $(objpfx)preloadtest
>> Missing dependency on the objects in $(tst-rtld-preload-OBJS), I think.

> I think not.  This is the same as preloadtest-ENV (without
> "LD_PRELOAD=").  Is it okay?  Should I have included a comment to
> explain this?

preloadtest.out has this:

$(objpfx)preloadtest.out: $(preloadtest-preloads:%=$(objpfx)%.so)
preloadtest-ENV = \
  LD_PRELOAD=$(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))

So I think you should add $(preloadtest-preloads:%=$(objpfx)%.so) as
well.

Thanks,
Florian
  
David Newall Nov. 7, 2018, 2:29 p.m. UTC | #4
On 8/11/18 12:36 am, Florian Weimer wrote:
> preloadtest.out has this:
>
> $(objpfx)preloadtest.out: $(preloadtest-preloads:%=$(objpfx)%.so)
> preloadtest-ENV = \
>    LD_PRELOAD=$(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
>
> So I think you should add $(preloadtest-preloads:%=$(objpfx)%.so) as
> well.

Oh, I see, yes, you are right.  Interesting that preloadtest.out does 
not depend on preloadtest.

This is a disincentive to use of $^ in the recipe. It should be like this?

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)

(or be explicit instead of $<)
  
Florian Weimer Nov. 8, 2018, 10:54 a.m. UTC | #5
* David Newall:

> On 8/11/18 12:36 am, Florian Weimer wrote:
>> preloadtest.out has this:
>>
>> $(objpfx)preloadtest.out: $(preloadtest-preloads:%=$(objpfx)%.so)
>> preloadtest-ENV = \
>>    LD_PRELOAD=$(subst $(empty) ,:,$(strip $(preloadtest-preloads:=.so)))
>>
>> So I think you should add $(preloadtest-preloads:%=$(objpfx)%.so) as
>> well.
>
> Oh, I see, yes, you are right.  Interesting that preloadtest.out does
> not depend on preloadtest.
>
> This is a disincentive to use of $^ in the recipe. It should be like this?
>
> 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)
>
> (or be explicit instead of $<)

Yes, you will have to use $<.  I do not have a strong preference ($< vs
tst-rtld-preload.sh).  The test runs in the source tree, so both are
okay.

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
+# <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