CVE-2025-15281: wordexp WRDE_REUSE uninitialized memory read

Resolves: RHEL-142788
This commit is contained in:
Florian Weimer 2026-02-12 15:11:11 +01:00
parent a4f5c93ccf
commit 9520284df9
2 changed files with 201 additions and 0 deletions

172
glibc-RHEL-142788-1.patch Normal file
View File

@ -0,0 +1,172 @@
commit 80cc58ea2de214f85b0a1d902a3b668ad2ecb302
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Jan 15 10:32:19 2026 -0300
posix: Reset wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814)
The wordexp fails to properly initialize the input wordexp_t when
WRDE_REUSE is used. The wordexp_t struct is properly freed, but
reuses the old wc_wordc value and updates the we_wordv in the
wrong position. A later wordfree will then call free with an
invalid pointer.
Checked on x86_64-linux-gnu and i686-linux-gnu.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
posix/Makefile
(Makefile not sorted downstream)
diff --git a/posix/Makefile b/posix/Makefile
index 562e8cb85fdb6f43..2dfd687430b205a8 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -113,7 +113,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-cpuset-dynamic \
tst-cpuset-static \
tst-spawn6 \
- tst-regcomp-bracket-free
+ tst-regcomp-bracket-free \
+ tst-wordexp-reuse
# Test for the glob symbol version that was replaced in glibc 2.27.
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
@@ -160,6 +161,7 @@ generated += $(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 10) \
bug-glob2.mtrace bug-glob2-mem.out tst-vfork3-mem.out \
tst-vfork3.mtrace getconf.speclist tst-fnmatch-mem.out \
tst-fnmatch.mtrace bug-regex36.mtrace \
+ tst-wordexp-reuse-mem.out tst-wordexp-reuse.mtrace \
testcases.h ptestcases.h
ifeq ($(run-built-tests),yes)
@@ -178,7 +180,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
$(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
$(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
$(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
- $(objpfx)tst-glob-tilde-mem.out $(objpfx)bug-ga2-mem.out
+ $(objpfx)tst-glob-tilde-mem.out $(objpfx)bug-ga2-mem.out \
+ $(objpfx)tst-wordexp-reuse.out
endif
include ../Rules
@@ -455,3 +458,10 @@ $(objpfx)posix-conf-vars-def.h: $(..)scripts/gen-posix-conf-vars.awk \
$(make-target-directory)
$(AWK) -f $(filter-out Makefile, $^) > $@.tmp
mv -f $@.tmp $@
+
+tst-wordexp-reuse-ENV += MALLOC_TRACE=$(objpfx)tst-wordexp-reuse.mtrace \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+
+$(objpfx)tst-wordexp-reuse-mem.out: $(objpfx)tst-wordexp-reuse.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-wordexp-reuse.mtrace > $@; \
+ $(evaluate-test)
diff --git a/posix/tst-wordexp-reuse.c b/posix/tst-wordexp-reuse.c
new file mode 100644
index 0000000000000000..3926b9f5576750ac
--- /dev/null
+++ b/posix/tst-wordexp-reuse.c
@@ -0,0 +1,89 @@
+/* Test for wordexp with WRDE_REUSE flag.
+ Copyright (C) 2026 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 <wordexp.h>
+#include <mcheck.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ mtrace ();
+
+ {
+ wordexp_t p = { 0 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { 0 };
+ TEST_COMPARE (wordexp ("one", &p, 0), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_APPEND), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
+ | WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ {
+ wordexp_t p = { .we_offs = 2 };
+ TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
+ TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
+ | WRDE_DOOFFS | WRDE_APPEND), 0);
+ TEST_COMPARE (p.we_wordc, 1);
+ TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
+ wordfree (&p);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 1f3b09f721bbee5c..b23608d4ee1cccd8 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -2220,7 +2220,9 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
{
/* Minimal implementation of WRDE_REUSE for now */
wordfree (pwordexp);
+ old_word.we_wordc = 0;
old_word.we_wordv = NULL;
+ pwordexp->we_wordc = 0;
}
if ((flags & WRDE_APPEND) == 0)

29
glibc-RHEL-142788-2.patch Normal file
View File

@ -0,0 +1,29 @@
commit bed2db02f3183e93f21d506786c5f884a1dec9e7
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jan 26 17:12:37 2026 +0100
posix: Run tst-wordexp-reuse-mem test
The test was not properly scheduled for execution with a Makefile
dependency.
Fixes commit 80cc58ea2de214f85b0a1d902a3b668ad2ecb302 ("posix: Reset
wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814").
Conflicts:
posix/Makefile
(Makefile not sorted downstream)
diff --git a/posix/Makefile b/posix/Makefile
index 2dfd687430b205a8..837fc26868ed74a8 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -181,7 +181,7 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
$(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
$(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
$(objpfx)tst-glob-tilde-mem.out $(objpfx)bug-ga2-mem.out \
- $(objpfx)tst-wordexp-reuse.out
+ $(objpfx)tst-wordexp-reuse-mem.out
endif
include ../Rules