ld.so: command argument "--preload"

Message ID e225cfd7-bfbb-13cd-9c6b-b25599360492@davidnewall.com
State New, archived
Headers

Commit Message

David Newall Oct. 10, 2018, 7:52 a.m. UTC
  Ping! (Copyright assignment now complete.)



-------- Forwarded Message --------
Subject: 	[PATCH] ld.so: command argument "--preload"
Date: 	Sat, 1 Sep 2018 00:16:30 +0930
From: 	David Newall <glibc@davidnewall.com>
To: 	libc-alpha@sourceware.org



Hello all,

I'm new here, so I'm probably doing this wrong.  Please tell me what I
should be doing.

CHANGE

Add a --preload command argument to ld.so (aka rtld.c)

RATIONALE

I worked around a deficiency in a 3rd party binary, via LD_PRELOAD,
however any sub-process invoked by that binary tried (as advertised) to
load the library, too.  When I needed to run the (32-bit) binary under a
64-bit OS, I found that the sub-processes worked, but elicited an ugly
error about wrong ELF class.  What I needed was a way of preloading a
library for only the binary that I was executing, and not for any
sub-process (e.g. executed via system(3)).

I feel that a --preload argument is a minor change on top of which the
LD_PRELOAD environment variable should be built.  That is, there should
be a way to preload a library without it propagating to all sub-processes.

Here is my patch.

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

Patch

--- elf/rtld.c.orig	2018-08-22 22:14:20.584489324 +0930
+++ elf/rtld.c	2018-08-22 22:17:22.151716644 +0930
@@ -745,6 +745,8 @@ 
  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
@@ -752,8 +754,9 @@ 
     (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;
@@ -777,7 +780,7 @@ 
  	++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;
  }
@@ -902,6 +905,13 @@ 
  	    _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;
  
@@ -930,7 +940,8 @@ 
  			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;
@@ -1536,7 +1547,16 @@ 
    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);