[PATCH] elf: Load files from /etc/ld.so.preload.d

Łukasz Stelmach stlman@poczta.fm
Tue Sep 29 11:50:12 GMT 2026


From: Łukasz Stelmach <l.stelmach@samsung.com>

Enable reading a list of libraries to preload from files in
/etc/ld.so.preload.d directory. The files must end in `.conf` to be read.

Fixes: https://sourceware.org/bugzilla/show_bug.cgi?id=24913
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 elf/rtld.c | 161 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 97 insertions(+), 64 deletions(-)

diff --git a/elf/rtld.c b/elf/rtld.c
index 324393d606..74387c2663 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -54,6 +54,8 @@
 #include <dl-audit-check.h>
 #include <dl-call_tls_init_tp.h>
 #include <dl-exec-post.h>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include <assert.h>
 
@@ -1841,80 +1843,111 @@ dl_main (const ElfW(Phdr) *phdr,
      the work but this does not matter, since it is not for production
      use.  */
   static const char preload_file[] = "/etc/ld.so.preload";
+  const size_t preload_dir_len = sizeof("/etc/ld.so.preload.d") - 1;
+  char preload_dir[sizeof("/etc/ld.so.preload.d") + 1 + sizeof(((struct dirent*)0)->d_name)] = "/etc/ld.so.preload.d";
+  const char *p_file = NULL;
+  DIR *p_dir = NULL;
+
   if (__glibc_unlikely (__access (preload_file, R_OK) == 0))
+    p_file = preload_file;
+
+  if (__glibc_unlikely (__access (preload_dir, R_OK | X_OK) == 0))
+    p_dir = opendir(preload_dir);
+
+  if (__glibc_unlikely (p_file != NULL || p_dir != NULL))
     {
-      /* Read the contents of the file.  */
-      file = _dl_sysdep_read_whole_file (preload_file, &file_size,
-					 PROT_READ | PROT_WRITE);
-      if (__glibc_unlikely (file != MAP_FAILED))
-	{
-	  /* Parse the file.  It contains names of libraries to be loaded,
-	     separated by white spaces or `:'.  It may also contain
-	     comments introduced by `#'.  */
-	  char *problem;
-	  char *runp;
-	  size_t rest;
-
-	  /* Eliminate comments.  */
-	  runp = file;
-	  rest = file_size;
-	  while (rest > 0)
-	    {
-	      char *comment = memchr (runp, '#', rest);
-	      if (comment == NULL)
-		break;
+      struct dirent* de = NULL;
+      do {
+	if (de != NULL)
+	  {
+	    int l = strlen(de->d_name);
+	    if (__glibc_unlikely ((l < sizeof(".conf") - 1)
+				  || (strncmp(".conf", &de->d_name[l - 5], 5) != 0)))
+	      continue;
+	    preload_dir[preload_dir_len] = '/';
+	    strncpy(&preload_dir[preload_dir_len + 1], de->d_name, sizeof(preload_dir) - preload_dir_len - 1);
+	    preload_dir[preload_dir_len + 1 + l] = '\0';
+	    p_file = preload_dir;
+	  }
 
-	      rest -= comment - runp;
-	      do
-		*comment = ' ';
-	      while (--rest > 0 && *++comment != '\n');
-	    }
+        if (p_file == NULL)
+	  continue;
 
-	  /* We have one problematic case: if we have a name at the end of
-	     the file without a trailing terminating characters, we cannot
-	     place the \0.  Handle the case separately.  */
-	  if (file[file_size - 1] != ' ' && file[file_size - 1] != '\t'
-	      && file[file_size - 1] != '\n' && file[file_size - 1] != ':')
-	    {
-	      problem = &file[file_size];
-	      while (problem > file && problem[-1] != ' '
-		     && problem[-1] != '\t'
-		     && problem[-1] != '\n' && problem[-1] != ':')
-		--problem;
-
-	      if (problem > file)
-		problem[-1] = '\0';
-	    }
-	  else
-	    {
-	      problem = NULL;
-	      file[file_size - 1] = '\0';
-	    }
+	/* Read the contents of the file.  */
+	file = _dl_sysdep_read_whole_file (p_file, &file_size,
+					   PROT_READ | PROT_WRITE);
+	if (__glibc_unlikely (file != MAP_FAILED))
+	  {
+	    /* Parse the file.  It contains names of libraries to be loaded,
+	       separated by white spaces or `:'.  It may also contain
+	       comments introduced by `#'.  */
+	    char *problem;
+	    char *runp;
+	    size_t rest;
+
+	    /* Eliminate comments.  */
+	    runp = file;
+	    rest = file_size;
+	    while (rest > 0)
+	      {
+		char *comment = memchr (runp, '#', rest);
+		if (comment == NULL)
+		  break;
+
+		rest -= comment - runp;
+		do
+		  *comment = ' ';
+		while (--rest > 0 && *++comment != '\n');
+	      }
 
-	  RTLD_TIMING_VAR (start);
-	  rtld_timer_start (&start);
+	    /* We have one problematic case: if we have a name at the end of
+	       the file without a trailing terminating characters, we cannot
+	       place the \0.  Handle the case separately.  */
+	    if (file[file_size - 1] != ' ' && file[file_size - 1] != '\t'
+		&& file[file_size - 1] != '\n' && file[file_size - 1] != ':')
+	      {
+		problem = &file[file_size];
+		while (problem > file && problem[-1] != ' '
+		       && problem[-1] != '\t'
+		       && problem[-1] != '\n' && problem[-1] != ':')
+		  --problem;
+
+		if (problem > file)
+		  problem[-1] = '\0';
+	      }
+	    else
+	      {
+		problem = NULL;
+		file[file_size - 1] = '\0';
+	      }
 
-	  if (file != problem)
-	    {
-	      char *p;
-	      runp = file;
-	      while ((p = strsep (&runp, ": \t\n")) != NULL)
-		if (p[0] != '\0')
-		  npreloads += do_preload (p, main_map, preload_file);
-	    }
+	    RTLD_TIMING_VAR (start);
+	    rtld_timer_start (&start);
 
-	  if (problem != NULL)
-	    {
-	      char *p = strndupa (problem, file_size - (problem - file));
+	    if (file != problem)
+	      {
+		char *p;
+		runp = file;
+		while ((p = strsep (&runp, ": \t\n")) != NULL)
+		  if (p[0] != '\0')
+		    npreloads += do_preload (p, main_map, p_file);
+	      }
 
-	      npreloads += do_preload (p, main_map, preload_file);
-	    }
+	    if (problem != NULL)
+	      {
+		char *p = strndupa (problem, file_size - (problem - file));
 
-	  rtld_timer_accum (&load_time, start);
+		npreloads += do_preload (p, main_map, p_file);
+	      }
 
-	  /* We don't need the file anymore.  */
-	  __munmap (file, file_size);
-	}
+	    rtld_timer_accum (&load_time, start);
+
+	    /* We don't need the file anymore.  */
+	    __munmap (file, file_size);
+	  }
+      } while (p_dir && (de = readdir(p_dir)));
+      if (p_dir != NULL)
+	closedir(p_dir);
     }
 
   if (__glibc_unlikely (*first_preload != NULL))
-- 
2.54.0



More information about the Libc-alpha mailing list