[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