[v2,1/2] rtld: Add --no-default-paths option

Message ID CAAjxMxeABu7Qs=vOu8D+=xSka=0ghr_kROOEC+y4XP=SzbcRqQ@mail.gmail.com
State Changes Requested, archived
Headers
Series [v2,1/2] rtld: Add --no-default-paths option |

Commit Message

Fergus Dall May 27, 2021, 1:55 p.m. UTC
  Changes from previous patchset: I've taken vapier's suggestion to use
positive variable names, added a NEWS entry, and a pair of tests. The
tests turned out to be much larger than the primary change, so I've
split them into a separate patch.

-- 8< --
This option causes the default library search path to be skipped,
using only the paths in DT_RPATH, LD_LIBRARY_PATH, and
DT_RUNPATH. This option implies --inhibit-cache, as there is no point
in searching a cache of system libraries when we are not using the
system libraries at all.

This is necessary to preserve negative search results when isolating
applications from the system libraries. This can be important when an
application uses dlopen at run time to load optional libraries.

When a shared library is required by the application, it can be
isolated by putting appropriate versions of the libraries in
directories specified in LD_LIBRARY_PATH, because the library search
will always terminate before potentially loading any system libraries.

On the other hand, if the application should be run without an
optional library, the search will proceed past the LD_LIBRARY_PATH
directories into the default system libraries, potentially causing an
incorrect library to be linked.
  

Comments

Florian Weimer May 27, 2021, 3:08 p.m. UTC | #1
* Fergus Dall via Libc-alpha:

> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
> index e383aa1dc3..f9f2c4126a 100644
> --- a/sysdeps/generic/ldsodefs.h
> +++ b/sysdeps/generic/ldsodefs.h
> @@ -551,6 +551,9 @@ struct rtld_global_ro
>    /* Do we read from ld.so.cache?  */
>    EXTERN int _dl_inhibit_cache;
>  
> +  /* Do we search the default system paths? */
> +  EXTERN int _dl_search_default_paths;

Maybe use a bool for this?

Thanks,
Florian
  
Joseph Myers May 27, 2021, 4:36 p.m. UTC | #2
On Thu, 27 May 2021, Fergus Dall via Libc-alpha wrote:

> +const char libc[] = "/libc.so.6";
> +const char libdl[] = "/libdl.so.2";

If these are meant to be the SONAMEs of libc and libdl (with "/" 
prepended), you should use LIBC_SO and LIBDL_SO from <gnu/lib-names.h>.  
Some configurations have different SONAMEs (look for libc= and libdl= in 
shlib-versions files).  Also watch out for any interaction with Florian's 
patches to move libdl into libc.

> +  strcpy(lib_src, support_slibdir_prefix);

Throughout this patch, there should be a space before '(' in function 
calls; tests should follow GNU style, like other glibc code.  (In the GCC 
and GDB testsuites, it's useful to have code with a range of different 
styles, to make sure those tools work well with such code, but that 
doesn't apply to the glibc testsuite.)

> +const char libc[] = "/libc.so.6";
> +const char libdl[] = "/libdl.so.2";

Same comment about using <gnu/lib-names.h> applies here.

> +int main(int argc, char *argv[]) {
> +  if (argc < 2) {
> +    FAIL_EXIT1(usage);
> +  }

Again, GNU style fixes.  Return type on its own line, space before '(', 
open braces on their own lines (and indented from the "if").
  
Fergus Dall June 6, 2021, 4:27 p.m. UTC | #3
None of the other options in that file use "bool" even when they seem
to only be used as booleans. I assumed this was out of a desire to
keep C89 compatibility, though now that I look I see lots of other
places in the codebase that don't do that.

On Fri, May 28, 2021 at 1:08 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * Fergus Dall via Libc-alpha:
>
> > diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
> > index e383aa1dc3..f9f2c4126a 100644
> > --- a/sysdeps/generic/ldsodefs.h
> > +++ b/sysdeps/generic/ldsodefs.h
> > @@ -551,6 +551,9 @@ struct rtld_global_ro
> >    /* Do we read from ld.so.cache?  */
> >    EXTERN int _dl_inhibit_cache;
> >
> > +  /* Do we search the default system paths? */
> > +  EXTERN int _dl_search_default_paths;
>
> Maybe use a bool for this?
>
> Thanks,
> Florian
>
  

Patch

From 61d66e7ddca5f7a2dedf240c940ccb76b45946a9 Mon Sep 17 00:00:00 2001
From: Fergus Dall <sidereal@google.com>
Date: Fri, 21 May 2021 17:16:38 +1000
Subject: [PATCH v2 1/2] rtld: Add --no-default-paths option
To: libc-alpha@sourceware.org
Cc: chromeos-toolchain@google.com,
    clumptini@google.com,
    vapier@google.com

This option causes the default library search path to be skipped,
using only the paths in DT_RPATH, LD_LIBRARY_PATH, and
DT_RUNPATH. This option implies --inhibit-cache, as there is no point
in searching a cache of system libraries when we are not using the
system libraries at all.

This is necessary to preserve negative search results when isolating
applications from the system libraries. This can be important when an
application uses dlopen at run time to load optional libraries.

When a shared library is required by the application, it can be
isolated by putting appropriate versions of the libraries in
directories specified in LD_LIBRARY_PATH, because the library search
will always terminate before potentially loading any system libraries.

On the other hand, if the application should be run without an
optional library, the search will proceed past the LD_LIBRARY_PATH
directories into the default system libraries, potentially causing an
incorrect library to be linked.
---
 NEWS                       |  4 ++++
 elf/dl-load.c              |  6 ++++--
 elf/dl-support.c           |  2 ++
 elf/dl-usage.c             |  2 ++
 elf/rtld.c                 | 10 ++++++++++
 sysdeps/generic/ldsodefs.h |  3 +++
 6 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index 266837bf2d..9fb4cf7e72 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,10 @@  Major new features:
 
 * The ISO C2X function timespec_getres has been added.
 
+* The dynamic linker has gained the --no-default-paths option, which
+  causes it to ignore libraries in the default system paths even if all
+  higher precedence locations have been searched.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The function pthread_mutex_consistent_np has been deprecated; programs
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 918ec7546c..cc02699bec 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2258,7 +2258,8 @@  _dl_map_object (struct link_map *loader, const char *name,
       if (fd == -1
 	  && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
 	      || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
-	  && __rtld_search_dirs.dirs != (void *) -1)
+	  && __rtld_search_dirs.dirs != (void *) -1
+	  && __glibc_likely (GLRO(dl_search_default_paths)))
 	fd = open_path (name, namelen, mode, &__rtld_search_dirs,
 			&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
 
@@ -2438,7 +2439,8 @@  _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
      a way to indicate that in the results for Dl_serinfo.  */
 
   /* Finally, try the default path.  */
-  if (!(loader->l_flags_1 & DF_1_NODEFLIB))
+  if (!(loader->l_flags_1 & DF_1_NODEFLIB)
+      && __glibc_likely (GLRO(dl_search_default_paths)))
     add_path (&p, &__rtld_search_dirs, XXX_default);
 
   if (counting)
diff --git a/elf/dl-support.c b/elf/dl-support.c
index dfc9ab760e..def75550aa 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -144,6 +144,8 @@  size_t _dl_minsigstacksize = CONSTANT_MINSIGSTKSZ;
 
 int _dl_inhibit_cache;
 
+int _dl_search_default_paths;
+
 unsigned int _dl_osversion;
 
 /* All known directories in sorted order.  */
diff --git a/elf/dl-usage.c b/elf/dl-usage.c
index 5ad3a72559..b5ae44932a 100644
--- a/elf/dl-usage.c
+++ b/elf/dl-usage.c
@@ -247,6 +247,8 @@  setting environment variables (which would be inherited by subprocesses).\n\
   --inhibit-cache       Do not use " LD_SO_CACHE "\n\
   --library-path PATH   use given PATH instead of content of the environment\n\
                         variable LD_LIBRARY_PATH\n\
+  --no-default-paths    do not use the default library search path\n\
+                        (this option implies --inhibit-cache)\n\
   --glibc-hwcaps-prepend LIST\n\
                         search glibc-hwcaps subdirectories in LIST\n\
   --glibc-hwcaps-mask LIST\n\
diff --git a/elf/rtld.c b/elf/rtld.c
index fbbd60b446..6f9bfcbadb 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -360,6 +360,7 @@  struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_fpu_control = _FPU_DEFAULT,
     ._dl_pagesize = EXEC_PAGESIZE,
     ._dl_inhibit_cache = 0,
+    ._dl_search_default_paths = 1,
 
     /* Function pointers.  */
     ._dl_debug_printf = _dl_debug_printf,
@@ -1204,6 +1205,15 @@  dl_main (const ElfW(Phdr) *phdr,
 	    _dl_argc -= 2;
 	    _dl_argv += 2;
 	  }
+        else if (! strcmp (_dl_argv[1], "--no-default-paths"))
+          {
+            GLRO(dl_search_default_paths) = 0;
+            GLRO(dl_inhibit_cache) = 1;
+
+	    ++_dl_skip_args;
+	    --_dl_argc;
+	    ++_dl_argv;
+          }
 	else if (! strcmp (_dl_argv[1], "--inhibit-rpath")
 		 && _dl_argc > 2)
 	  {
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index e383aa1dc3..f9f2c4126a 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -551,6 +551,9 @@  struct rtld_global_ro
   /* Do we read from ld.so.cache?  */
   EXTERN int _dl_inhibit_cache;
 
+  /* Do we search the default system paths? */
+  EXTERN int _dl_search_default_paths;
+
   /* Copy of the content of `_dl_main_searchlist' at startup time.  */
   EXTERN struct r_scope_elem _dl_initial_searchlist;
 
-- 
2.31.1.818.g46aad6cb9e-goog