File wordexp-wrde-reuse.patch of Package glibc.42654

From c0d2ba81e5ba60cdb3da8e72e45c005a91db0ba0 Mon Sep 17 00:00:00 2001
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu, 15 Jan 2026 10:32:19 -0300
Subject: [PATCH] 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>
(cherry picked from commit 80cc58ea2de214f85b0a1d902a3b668ad2ecb302)
---
 posix/Makefile            | 16 +++++--
 posix/tst-wordexp-reuse.c | 89 +++++++++++++++++++++++++++++++++++++++
 posix/wordexp.c           |  2 +
 3 files changed, 103 insertions(+), 4 deletions(-)
 create mode 100644 posix/tst-wordexp-reuse.c

Index: glibc-2.22/posix/Makefile
===================================================================
--- glibc-2.22.orig/posix/Makefile
+++ glibc-2.22/posix/Makefile
@@ -87,7 +87,8 @@ tests		:= tstgetopt testfnm runtests run
 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
 		   bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
 		   tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
-		   tst-fnmatch3 bug-regex36 tst-getaddrinfo5 tst-glob-tilde
+		   tst-fnmatch3 bug-regex36 tst-getaddrinfo5 tst-glob-tilde \
+		   tst-wordexp-reuse
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
@@ -113,11 +114,13 @@ generated += $(addprefix wordexp-test-re
 	     tst-boost.mtrace bug-ga2.mtrace bug-ga2-mem.out \
 	     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-fnmatch.mtrace bug-regex36.mtrace tst-wordexp-reuse-mem.out \
+	     tst-wordexp-reuse.mtrace
 
 ifeq ($(run-built-tests),yes)
 ifeq (yes,$(build-shared))
-tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out
+tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out \
+		 $(objpfx)wordexp-tst.out
 endif
 endif
 
@@ -131,7 +134,7 @@ tests-special += $(objpfx)bug-regex2-mem
 		 $(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)tst-glob-tilde-mem.out $(objpfx)tst-wordexp-reuse.out
 xtests-special += $(objpfx)bug-ga2-mem.out
 endif
 
@@ -338,3 +341,9 @@ $(objpfx)posix-conf-vars-def.h: $(..)scr
 	$(make-target-directory)
 	$(AWK) -f $(filter-out Makefile, $^) > $@.tmp
 	mv -f $@.tmp $@
+
+tst-wordexp-reuse-ENV += MALLOC_TRACE=$(objpfx)tst-wordexp-reuse.mtrace
+
+$(objpfx)tst-wordexp-reuse-mem.out: $(objpfx)tst-wordexp-reuse.out
+	$(common-objpfx)malloc/mtrace $(objpfx)tst-wordexp-reuse.mtrace > $@; \
+	$(evaluate-test)
Index: glibc-2.22/posix/tst-wordexp-reuse.c
===================================================================
--- /dev/null
+++ glibc-2.22/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>
Index: glibc-2.22/posix/wordexp.c
===================================================================
--- glibc-2.22.orig/posix/wordexp.c
+++ glibc-2.22/posix/wordexp.c
@@ -2252,7 +2252,9 @@ wordexp (const char *words, wordexp_t *p
     {
       /* 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)
openSUSE Build Service is sponsored by