From 32917e7ee972e7a01127a04454f12ef31dc312ed Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 11 Jun 2025 03:19:10 -0700 Subject: [PATCH] elf: Ignore LD_LIBRARY_PATH and debug env var for setuid for static It mimics the ld.so behavior. Checked on x86_64-linux-gnu. [New Test Case] elf: Test case for bug 32976 [https://sourceware.org/bugzilla/show_bug.cgi?id=32976] Check that LD_LIBRARY_PATH is ignored for AT_SECURE statically linked binaries, using support_capture_subprogram_self_sgid. Upstream-Status: Backport [https://sourceware.org/cgit/glibc/commit/?id=5451fa962cd0a90a0e2ec1d8910a559ace02bba0 && https://sourceware.org/cgit/glibc/commit/?id=d8f7a79335b0d861c12c42aec94c04cd5bb181e2] CVE: CVE-2025-4802 Co-authored-by: Florian Weimer Signed-off-by: Sunil Dora --- elf/Makefile | 4 ++ elf/dl-support.c | 46 ++++++++--------- elf/tst-dlopen-sgid-mod.c | 1 + elf/tst-dlopen-sgid.c | 104 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 23 deletions(-) create mode 100644 elf/tst-dlopen-sgid-mod.c create mode 100644 elf/tst-dlopen-sgid.c diff --git a/elf/Makefile b/elf/Makefile index 61c41ea6..3ad66ab6 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -274,6 +274,7 @@ tests-static-normal := \ tst-array1-static \ tst-array5-static \ tst-dl-iter-static \ + tst-dlopen-sgid \ tst-dst-static \ tst-env-setuid \ tst-env-setuid-tunables \ @@ -807,6 +808,7 @@ modules-names = \ tst-dlmopen-gethostbyname-mod \ tst-dlmopen-twice-mod1 \ tst-dlmopen-twice-mod2 \ + tst-dlopen-sgid-mod \ tst-dlopenfaillinkmod \ tst-dlopenfailmod1 \ tst-dlopenfailmod2 \ @@ -2913,3 +2915,5 @@ $(objpfx)tst-recursive-tls.out: \ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) $(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c $(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$* + +$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so diff --git a/elf/dl-support.c b/elf/dl-support.c index 09079c12..c2baed69 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -272,8 +272,6 @@ _dl_non_dynamic_init (void) _dl_main_map.l_phdr = GL(dl_phdr); _dl_main_map.l_phnum = GL(dl_phnum); - _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; - /* Set up the data structures for the system-supplied DSO early, so they can influence _dl_init_paths. */ setup_vdso (NULL, NULL); @@ -281,27 +279,6 @@ _dl_non_dynamic_init (void) /* With vDSO setup we can initialize the function pointers. */ setup_vdso_pointers (); - /* Initialize the data structures for the search paths for shared - objects. */ - _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", - /* No glibc-hwcaps selection support in statically - linked binaries. */ - NULL, NULL); - - /* Remember the last search directory added at startup. */ - _dl_init_all_dirs = GL(dl_all_dirs); - - _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; - - _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; - - _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; - - _dl_profile_output = getenv ("LD_PROFILE_OUTPUT"); - if (_dl_profile_output == NULL || _dl_profile_output[0] == '\0') - _dl_profile_output - = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; - if (__libc_enable_secure) { static const char unsecure_envvars[] = @@ -324,6 +301,29 @@ _dl_non_dynamic_init (void) #endif } + _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + + /* Initialize the data structures for the search paths for shared + objects. */ + _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH", + /* No glibc-hwcaps selection support in statically + linked binaries. */ + NULL, NULL); + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = GL(dl_all_dirs); + + _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; + + _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; + + _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; + + _dl_profile_output = getenv ("LD_PROFILE_OUTPUT"); + if (_dl_profile_output == NULL || _dl_profile_output[0] == '\0') + _dl_profile_output + = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; + #ifdef DL_PLATFORM_INIT DL_PLATFORM_INIT; #endif diff --git a/elf/tst-dlopen-sgid-mod.c b/elf/tst-dlopen-sgid-mod.c new file mode 100644 index 00000000..5eb79eef --- /dev/null +++ b/elf/tst-dlopen-sgid-mod.c @@ -0,0 +1 @@ +/* Opening this object should not succeed. */ diff --git a/elf/tst-dlopen-sgid.c b/elf/tst-dlopen-sgid.c new file mode 100644 index 00000000..47829a40 --- /dev/null +++ b/elf/tst-dlopen-sgid.c @@ -0,0 +1,104 @@ +/* Test case for ignored LD_LIBRARY_PATH in static startug (bug 32976). + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* This is the name of our test object. Use a custom module for + testing, so that this object does not get picked up from the system + path. */ +static const char dso_name[] = "tst-dlopen-sgid-mod.so"; + +/* Used to mark the recursive invocation. */ +static const char magic_argument[] = "run-actual-test"; + +static int +do_test (void) +{ +/* Pathname of the directory that receives the shared objects this + test attempts to load. */ + char *libdir = support_create_temp_directory ("tst-dlopen-sgid-"); + + /* This is supposed to be ignored and stripped. */ + TEST_COMPARE (setenv ("LD_LIBRARY_PATH", libdir, 1), 0); + + /* Copy of libc.so.6. */ + { + char *from = xasprintf ("%s/%s", support_objdir_root, LIBC_SO); + char *to = xasprintf ("%s/%s", libdir, LIBC_SO); + add_temp_file (to); + support_copy_file (from, to); + free (to); + free (from); + } + + /* Copy of the test object. */ + { + char *from = xasprintf ("%s/elf/%s", support_objdir_root, dso_name); + char *to = xasprintf ("%s/%s", libdir, dso_name); + add_temp_file (to); + support_copy_file (from, to); + free (to); + free (from); + } + + TEST_COMPARE (support_capture_subprogram_self_sgid (magic_argument), 0); + + free (libdir); + + return 0; +} + +static void +alternative_main (int argc, char **argv) +{ + if (argc == 2 && strcmp (argv[1], magic_argument) == 0) + { + if (getgid () == getegid ()) + /* This can happen if the file system is mounted nosuid. */ + FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", + (intmax_t) getgid ()); + + /* Should be removed due to SGID. */ + TEST_COMPARE_STRING (getenv ("LD_LIBRARY_PATH"), NULL); + + TEST_VERIFY (dlopen (dso_name, RTLD_NOW) == NULL); + { + const char *message = dlerror (); + TEST_COMPARE_STRING (message, + "tst-dlopen-sgid-mod.so:" + " cannot open shared object file:" + " No such file or directory"); + } + + support_record_failure_barrier (); + exit (EXIT_SUCCESS); + } +} + +#define PREPARE alternative_main +#include -- 2.49.0