CVE-2025-4802: static setuid dlopen may search LD_LIBRARY_PATH (RHEL-92685)

Resolves: RHEL-92685
Reviewed-by: Frédéric Bérat <fberat@redhat.com>
This commit is contained in:
Florian Weimer 2025-05-26 17:25:07 +02:00
parent b533a4ebd0
commit 696da51adf
10 changed files with 892 additions and 1 deletions

23
glibc-RHEL-92685-1.patch Normal file
View File

@ -0,0 +1,23 @@
commit 45caed9d67a00af917d8b5b88d4b5eb1225b7aef
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue Aug 3 21:10:53 2021 +0530
copy_and_spawn_sgid: Avoid double calls to close()
If close() on infd and outfd succeeded, reset the fd numbers so that
we don't attempt to close them again.
Reviewed-by: Arjun Shankar <arjun@redhat.com>
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index eec5371d5602aa29..9da5ba0c10bf6eee 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -169,6 +169,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
support_subprogram because we only want the program exit status, not the
contents. */
ret = 0;
+ infd = outfd = -1;
char * const args[] = {execname, child_id, NULL};

52
glibc-RHEL-92685-2.patch Normal file
View File

@ -0,0 +1,52 @@
commit 6286cca2cb8389dcffec39238a8bf15ffea96396
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Jun 1 07:23:15 2023 -0400
support: Don't fail on fchown when spawning sgid processes
In some cases (e.g. when podman creates user containers), the only other
group assigned to the executing user is nobody and fchown fails with it
because the group is not mapped. Do not fail the test in this case,
instead exit as unsupported.
Reported-by: Frédéric Bérat <fberat@redhat.com>
Tested-by: Frédéric Bérat <fberat@redhat.com>
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 9da5ba0c10bf6eee..af03ea4dc6ec0b95 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -152,9 +152,18 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
p += wrcount;
}
}
- TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
+
+ bool chowned = false;
+ TEST_VERIFY ((chowned = fchown (outfd, getuid (), gid) == 0)
+ || errno == EPERM);
if (support_record_failure_is_failed ())
goto err;
+ else if (!chowned)
+ {
+ ret = 77;
+ goto err;
+ }
+
TEST_VERIFY (fchmod (outfd, 02750) == 0);
if (support_record_failure_is_failed ())
goto err;
@@ -191,8 +200,10 @@ err:
free (dirname);
}
+ if (ret == 77)
+ FAIL_UNSUPPORTED ("Failed to make sgid executable for test\n");
if (ret != 0)
- FAIL_EXIT1("Failed to make sgid executable for test\n");
+ FAIL_EXIT1 ("Failed to make sgid executable for test\n");
return status;
}

86
glibc-RHEL-92685-3.patch Normal file
View File

@ -0,0 +1,86 @@
commit 5451fa962cd0a90a0e2ec1d8910a559ace02bba0
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Nov 6 17:25:49 2023 -0300
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.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflicts:
elf/dl-support.c
(downstream still uses HAVE_TUNABLES, does not yet
call setup_vdso_pointers, still supports
EXTRA_UNSECURE_ENVVARS)
diff --git a/elf/dl-support.c b/elf/dl-support.c
index e9943e889ef447ad..008fd90cb43c8803 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -314,33 +314,10 @@ _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);
- /* 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[] =
@@ -363,6 +340,30 @@ _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

41
glibc-RHEL-92685-4.patch Normal file
View File

@ -0,0 +1,41 @@
commit d0b8aa6de4529231fadfe604ac2c434e559c2d9e
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Dec 23 13:57:55 2024 +0100
support: Add support_record_failure_barrier
This can be used to stop execution after a TEST_COMPARE_BLOB
failure, for example.
diff --git a/support/check.h b/support/check.h
index 7ea9a86a9c7ed055..d435479963945bb9 100644
--- a/support/check.h
+++ b/support/check.h
@@ -187,6 +187,9 @@ void support_record_failure_reset (void);
failures or not. */
int support_record_failure_is_failed (void);
+/* Terminate the process if any failures have been encountered so far. */
+void support_record_failure_barrier (void);
+
__END_DECLS
#endif /* SUPPORT_CHECK_H */
diff --git a/support/support_record_failure.c b/support/support_record_failure.c
index 17ab1d80ef2bbdea..8d0f3852dcf60a70 100644
--- a/support/support_record_failure.c
+++ b/support/support_record_failure.c
@@ -112,3 +112,13 @@ support_record_failure_is_failed (void)
synchronization for reliable test error reporting anyway. */
return __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
}
+
+void
+support_record_failure_barrier (void)
+{
+ if (__atomic_load_n (&state->failed, __ATOMIC_RELAXED))
+ {
+ puts ("error: exiting due to previous errors");
+ exit (1);
+ }
+}

56
glibc-RHEL-92685-5.patch Normal file
View File

@ -0,0 +1,56 @@
commit f0c09fe61678df6f7f18fe1ebff074e62fa5ca7a
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue May 20 19:36:02 2025 +0200
support: Use const char * argument in support_capture_subprogram_self_sgid
The function does not modify the passed-in string, so make this clear
via the prototype.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
index 72fb30504684a84e..67c0cd82597805bd 100644
--- a/support/capture_subprocess.h
+++ b/support/capture_subprocess.h
@@ -44,8 +44,7 @@ struct support_capture_subprocess support_capture_subprogram
/* Copy the running program into a setgid binary and run it with CHILD_ID
argument. If execution is successful, return the exit status of the child
program, otherwise return a non-zero failure exit code. */
-int support_capture_subprogram_self_sgid
- (char *child_id);
+int support_capture_subprogram_self_sgid (const char *child_id);
/* Deallocate the subprocess data captured by
support_capture_subprocess. */
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index af03ea4dc6ec0b95..48c2ab839dca33ea 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -108,7 +108,7 @@ support_capture_subprogram (const char *file, char *const argv[])
safely make it SGID with the TARGET group ID. Then runs the
executable. */
static int
-copy_and_spawn_sgid (char *child_id, gid_t gid)
+copy_and_spawn_sgid (const char *child_id, gid_t gid)
{
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
test_dir, (intmax_t) getpid ());
@@ -180,7 +180,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
ret = 0;
infd = outfd = -1;
- char * const args[] = {execname, child_id, NULL};
+ char * const args[] = {execname, (char *) child_id, NULL};
status = support_subprogram_wait (args[0], args);
@@ -209,7 +209,7 @@ err:
}
int
-support_capture_subprogram_self_sgid (char *child_id)
+support_capture_subprogram_self_sgid (const char *child_id)
{
gid_t target = 0;
const int count = 64;

159
glibc-RHEL-92685-6.patch Normal file
View File

@ -0,0 +1,159 @@
commit d8f7a79335b0d861c12c42aec94c04cd5bb181e2
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue May 20 19:36:02 2025 +0200
elf: Test case for bug 32976 (CVE-2025-4802)
Check that LD_LIBRARY_PATH is ignored for AT_SECURE statically
linked binaries, using support_capture_subprogram_self_sgid.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/Makefile
((test list differences, link against libdl))
diff --git a/elf/Makefile b/elf/Makefile
index 8ca9f1c13f78216d..38976f195a398abf 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -235,6 +235,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 \
@@ -726,6 +727,7 @@ modules-names = \
tst-dlmopen-gethostbyname-mod \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
+ tst-dlopen-sgid-mod \
tst-dlopen-tlsreinitmod1 \
tst-dlopen-tlsreinitmod2 \
tst-dlopen-tlsreinitmod3 \
@@ -2816,3 +2818,6 @@ $(objpfx)tst-dlopen-tlsreinit3.out: $(objpfx)tst-auditmod1.so
tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
+
+$(objpfx)tst-dlopen-sgid: $(common-objpfx)dlfcn/libdl.a
+$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
diff --git a/elf/tst-dlopen-sgid-mod.c b/elf/tst-dlopen-sgid-mod.c
new file mode 100644
index 0000000000000000..5eb79eef485da4c9
--- /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 0000000000000000..47829a405e90b6b9
--- /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
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <unistd.h>
+
+/* 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 <support/test-driver.c>

42
glibc-RHEL-92685-7.patch Normal file
View File

@ -0,0 +1,42 @@
commit 35fc356fa3b4f485bd3ba3114c9f774e5df7d3c2
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed May 21 08:43:32 2025 +0200
elf: Fix subprocess status handling for tst-dlopen-sgid (bug 32987)
This should really move into support_capture_subprogram_self_sgid.
Reviewed-by: Sam James <sam@gentoo.org>
diff --git a/elf/tst-dlopen-sgid.c b/elf/tst-dlopen-sgid.c
index 47829a405e90b6b9..5688b79f2e870b1d 100644
--- a/elf/tst-dlopen-sgid.c
+++ b/elf/tst-dlopen-sgid.c
@@ -26,6 +26,8 @@
#include <support/check.h>
#include <support/support.h>
#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <sys/wait.h>
#include <unistd.h>
/* This is the name of our test object. Use a custom module for
@@ -66,10 +68,16 @@ do_test (void)
free (from);
}
- TEST_COMPARE (support_capture_subprogram_self_sgid (magic_argument), 0);
-
free (libdir);
+ int status = support_capture_subprogram_self_sgid (magic_argument);
+
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ if (!WIFEXITED (status))
+ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+
return 0;
}

105
glibc-RHEL-92685-8.patch Normal file
View File

@ -0,0 +1,105 @@
commit 2f769cec448d84a62b7dd0d4ff56978fe22c0cd6
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed May 21 16:47:34 2025 +0200
support: Pick group in support_capture_subprogram_self_sgid if UID == 0
When running as root, it is likely that we can run under any group.
Pick a harmless group from /etc/group in this case.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 48c2ab839dca33ea..774deacd5fe2b6cc 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -21,7 +21,11 @@
#include <errno.h>
#include <fcntl.h>
+#include <grp.h>
+#include <scratch_buffer.h>
+#include <stdio_ext.h>
#include <stdlib.h>
+#include <string.h>
#include <support/check.h>
#include <support/xunistd.h>
#include <support/xsocket.h>
@@ -208,10 +212,48 @@ err:
return status;
}
+/* Returns true if a group with NAME has been found, and writes its
+ GID to *TARGET. */
+static bool
+find_sgid_group (gid_t *target, const char *name)
+{
+ /* Do not use getgrname_r because it does not work in statically
+ linked binaries if the system libc is different. */
+ FILE *fp = fopen ("/etc/group", "rce");
+ if (fp == NULL)
+ return false;
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+ bool ok = false;
+ struct scratch_buffer buf;
+ scratch_buffer_init (&buf);
+ while (true)
+ {
+ struct group grp;
+ struct group *result = NULL;
+ int status = fgetgrent_r (fp, &grp, buf.data, buf.length, &result);
+ if (status == 0 && result != NULL)
+ {
+ if (strcmp (result->gr_name, name) == 0)
+ {
+ *target = result->gr_gid;
+ ok = true;
+ break;
+ }
+ }
+ else if (errno != ERANGE)
+ break;
+ else if (!scratch_buffer_grow (&buf))
+ break;
+ }
+ scratch_buffer_free (&buf);
+ fclose (fp);
+ return ok;
+}
+
int
support_capture_subprogram_self_sgid (const char *child_id)
{
- gid_t target = 0;
const int count = 64;
gid_t groups[count];
@@ -223,6 +265,7 @@ support_capture_subprogram_self_sgid (const char *child_id)
(intmax_t) getuid ());
gid_t current = getgid ();
+ gid_t target = current;
for (int i = 0; i < ret; ++i)
{
if (groups[i] != current)
@@ -232,9 +275,16 @@ support_capture_subprogram_self_sgid (const char *child_id)
}
}
- if (target == 0)
- FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
- (intmax_t) getuid ());
+ if (target == current)
+ {
+ /* If running as root, try to find a harmless group for SGID. */
+ if (getuid () != 0
+ || (!find_sgid_group (&target, "nogroup")
+ && !find_sgid_group (&target, "bin")
+ && !find_sgid_group (&target, "daemon")))
+ FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
+ (intmax_t) getuid ());
+ }
return copy_and_spawn_sgid (child_id, target);
}

315
glibc-RHEL-92685-9.patch Normal file
View File

@ -0,0 +1,315 @@
commit 3a3fb2ed83f79100c116c824454095ecfb335ad7
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu May 22 14:36:37 2025 +0200
Fix error reporting (false negatives) in SGID tests
And simplify the interface of support_capture_subprogram_self_sgid.
Use the existing framework for temporary directories (now with
mode 0700) and directory/file deletion. Handle all execution
errors within support_capture_subprogram_self_sgid. In particular,
this includes test failures because the invoked program did not
exit with exit status zero. Existing tests that expect exit
status 42 are adjusted to use zero instead.
In addition, fix callers not to call exit (0) with test failures
pending (which may mask them, especially when running with --direct).
Fixes commit 35fc356fa3b4f485bd3ba3114c9f774e5df7d3c2
("elf: Fix subprocess status handling for tst-dlopen-sgid (bug 32987)").
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/tst-env-setuid.c
(missing commit 11f7e3dd8fed66e0b8740af440cd3151e55a466f
("elf: Add all malloc tunable to unsecvars") downstream)
diff --git a/elf/tst-dlopen-sgid.c b/elf/tst-dlopen-sgid.c
index 5688b79f2e870b1d..8aec52e19fc56aba 100644
--- a/elf/tst-dlopen-sgid.c
+++ b/elf/tst-dlopen-sgid.c
@@ -70,13 +70,7 @@ do_test (void)
free (libdir);
- int status = support_capture_subprogram_self_sgid (magic_argument);
-
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (!WIFEXITED (status))
- FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+ support_capture_subprogram_self_sgid (magic_argument);
return 0;
}
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 8b0861c4ad853040..dfbea3118fa9daf8 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -127,10 +127,7 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
-
- /* Special return code to make sure that the child executed all the way
- through. */
- exit (42);
+ return 0;
}
else
{
@@ -149,18 +146,7 @@ do_test (int argc, char **argv)
continue;
}
- int status = support_capture_subprogram_self_sgid (buf);
-
- /* Bail out early if unsupported. */
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (WEXITSTATUS (status) != 42)
- {
- printf (" [%d] child failed with status %d\n", i,
- WEXITSTATUS (status));
- support_record_failure ();
- }
+ support_capture_subprogram_self_sgid (buf);
}
return 0;
}
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
index eda87f9dda293e79..04f6b0025fc86cfa 100644
--- a/elf/tst-env-setuid.c
+++ b/elf/tst-env-setuid.c
@@ -103,21 +103,14 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
-
- exit (EXIT_SUCCESS);
+ return 0;
}
else
{
if (test_parent () != 0)
exit (1);
- int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
-
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (!WIFEXITED (status))
- FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+ support_capture_subprogram_self_sgid (SETGID_CHILD);
return 0;
}
diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c
index 156c92fea216729f..bda73a203498a90f 100644
--- a/stdlib/tst-secure-getenv.c
+++ b/stdlib/tst-secure-getenv.c
@@ -57,13 +57,7 @@ do_test (void)
exit (1);
}
- int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
-
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (!WIFEXITED (status))
- FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+ support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
return 0;
}
@@ -82,6 +76,7 @@ alternative_main (int argc, char **argv)
if (secure_getenv ("PATH") != NULL)
FAIL_EXIT (4, "PATH variable not filtered out\n");
+ support_record_failure_barrier ();
exit (EXIT_SUCCESS);
}
}
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
index 67c0cd82597805bd..a7eef351ce1b276c 100644
--- a/support/capture_subprocess.h
+++ b/support/capture_subprocess.h
@@ -41,10 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
struct support_capture_subprocess support_capture_subprogram
(const char *file, char *const argv[]);
-/* Copy the running program into a setgid binary and run it with CHILD_ID
- argument. If execution is successful, return the exit status of the child
- program, otherwise return a non-zero failure exit code. */
-int support_capture_subprogram_self_sgid (const char *child_id);
+/* Copy the running program into a setgid binary and run it with
+ CHILD_ID argument. If the program exits with a non-zero status,
+ exit with that exit status (or status 1 if the program did not exit
+ normally). If the test cannot be performed, exit with
+ EXIT_UNSUPPORTED. */
+void support_capture_subprogram_self_sgid (const char *child_id);
/* Deallocate the subprocess data captured by
support_capture_subprocess. */
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
index 774deacd5fe2b6cc..25f79b760a9e414d 100644
--- a/support/support_capture_subprocess.c
+++ b/support/support_capture_subprocess.c
@@ -31,6 +31,7 @@
#include <support/xsocket.h>
#include <support/xspawn.h>
#include <support/support.h>
+#include <support/temp_file.h>
#include <support/test-driver.h>
static void
@@ -111,105 +112,44 @@ support_capture_subprogram (const char *file, char *const argv[])
/* Copies the executable into a restricted directory, so that we can
safely make it SGID with the TARGET group ID. Then runs the
executable. */
-static int
+static void
copy_and_spawn_sgid (const char *child_id, gid_t gid)
{
- char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
- test_dir, (intmax_t) getpid ());
+ char *dirname = support_create_temp_directory ("tst-glibc-sgid-");
char *execname = xasprintf ("%s/bin", dirname);
- int infd = -1;
- int outfd = -1;
- int ret = 1, status = 1;
-
- TEST_VERIFY (mkdir (dirname, 0700) == 0);
- if (support_record_failure_is_failed ())
- goto err;
+ add_temp_file (execname);
- infd = open ("/proc/self/exe", O_RDONLY);
- if (infd < 0)
+ if (access ("/proc/self/exe", R_OK) != 0)
FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
- TEST_VERIFY (outfd >= 0);
- if (support_record_failure_is_failed ())
- goto err;
-
- char buf[4096];
- for (;;)
- {
- ssize_t rdcount = read (infd, buf, sizeof (buf));
- TEST_VERIFY (rdcount >= 0);
- if (support_record_failure_is_failed ())
- goto err;
- if (rdcount == 0)
- break;
- char *p = buf;
- char *end = buf + rdcount;
- while (p != end)
- {
- ssize_t wrcount = write (outfd, buf, end - p);
- if (wrcount == 0)
- errno = ENOSPC;
- TEST_VERIFY (wrcount > 0);
- if (support_record_failure_is_failed ())
- goto err;
- p += wrcount;
- }
- }
+ support_copy_file ("/proc/self/exe", execname);
- bool chowned = false;
- TEST_VERIFY ((chowned = fchown (outfd, getuid (), gid) == 0)
- || errno == EPERM);
- if (support_record_failure_is_failed ())
- goto err;
- else if (!chowned)
- {
- ret = 77;
- goto err;
- }
+ if (chown (execname, getuid (), gid) != 0)
+ FAIL_UNSUPPORTED ("cannot change group of \"%s\" to %jd: %m",
+ execname, (intmax_t) gid);
- TEST_VERIFY (fchmod (outfd, 02750) == 0);
- if (support_record_failure_is_failed ())
- goto err;
- TEST_VERIFY (close (outfd) == 0);
- if (support_record_failure_is_failed ())
- goto err;
- TEST_VERIFY (close (infd) == 0);
- if (support_record_failure_is_failed ())
- goto err;
+ if (chmod (execname, 02750) != 0)
+ FAIL_UNSUPPORTED ("cannot make \"%s\" SGID: %m ", execname);
/* We have the binary, now spawn the subprocess. Avoid using
support_subprogram because we only want the program exit status, not the
contents. */
- ret = 0;
- infd = outfd = -1;
char * const args[] = {execname, (char *) child_id, NULL};
+ int status = support_subprogram_wait (args[0], args);
- status = support_subprogram_wait (args[0], args);
+ free (execname);
+ free (dirname);
-err:
- if (outfd >= 0)
- close (outfd);
- if (infd >= 0)
- close (infd);
- if (execname != NULL)
- {
- unlink (execname);
- free (execname);
- }
- if (dirname != NULL)
+ if (WIFEXITED (status))
{
- rmdir (dirname);
- free (dirname);
+ if (WEXITSTATUS (status) == 0)
+ return;
+ else
+ exit (WEXITSTATUS (status));
}
-
- if (ret == 77)
- FAIL_UNSUPPORTED ("Failed to make sgid executable for test\n");
- if (ret != 0)
- FAIL_EXIT1 ("Failed to make sgid executable for test\n");
-
- return status;
+ else
+ FAIL_EXIT1 ("subprogram failed with status %d", status);
}
/* Returns true if a group with NAME has been found, and writes its
@@ -251,7 +191,7 @@ find_sgid_group (gid_t *target, const char *name)
return ok;
}
-int
+void
support_capture_subprogram_self_sgid (const char *child_id)
{
const int count = 64;
@@ -286,7 +226,7 @@ support_capture_subprogram_self_sgid (const char *child_id)
(intmax_t) getuid ());
}
- return copy_and_spawn_sgid (child_id, target);
+ copy_and_spawn_sgid (child_id, target);
}
void

View File

@ -115,7 +115,7 @@ end \
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: %{glibcrelease}.21
Release: %{glibcrelease}.22
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@ -1268,6 +1268,15 @@ Patch1033: glibc-RHEL-86018-1.patch
Patch1034: glibc-RHEL-86018-2.patch
Patch1035: glibc-RHEL-88813.patch
Patch1036: glibc-RHEL-71921.patch
Patch1037: glibc-RHEL-92685-1.patch
Patch1038: glibc-RHEL-92685-2.patch
Patch1039: glibc-RHEL-92685-3.patch
Patch1040: glibc-RHEL-92685-4.patch
Patch1041: glibc-RHEL-92685-5.patch
Patch1042: glibc-RHEL-92685-6.patch
Patch1043: glibc-RHEL-92685-7.patch
Patch1044: glibc-RHEL-92685-8.patch
Patch1045: glibc-RHEL-92685-9.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2929,6 +2938,9 @@ fi
%{_libdir}/libpthread_nonshared.a
%changelog
* Mon May 26 2025 Florian Weimer <fweimer@redhat.com> - 2.28-251.22
- CVE-2025-4802: static setuid dlopen may search LD_LIBRARY_PATH (RHEL-92685)
* Wed May 14 2025 Patsy Griffin <patsy@redhat.com> - 2.28-251.21
- elf: Keep using minimal malloc after early DTV resize (RHEL-71921)