[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1109941: unblock: glibc/2.41-11 (pre-approval)



Package: release.debian.org
Severity: normal
X-Debbugs-Cc: glibc@packages.debian.org
Control: affects -1 + src:glibc
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package glibc

[ Reason ]
The reason that triggered this upload is a security issue in regcomp
(CVE-2025-8058) that got fixed in the upstream stable branch. It also
includes a fix for iconv creating files with the wrong permissions.

[ Impact ]
If the unblock isn't granted, systems will be vulnerable to
CVE-2025-8058.

[ Tests ]
Tests have been added for both changes, and actually represent the
largest part of the debdiff.

[ Risks ]
Risks are quite low, besides the new tests, changes are small, easily
reviewable and covered by additional tests.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
If it comes to late for the initial Trixie release, this
could go in the first point release.

unblock glibc/2.41-11
diff --git a/debian/changelog b/debian/changelog
index 4ee8be6e..85356f8e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+glibc (2.41-11) unstable; urgency=medium
+
+  * debian/patches/git-updates.diff: update from upstream stable branch:
+    - Fix iconv to not create executable files with -o.
+    - Fix double-free after allocation failure in regcomp (GLIBC-SA-2025-0005
+      / CVE-2025-8058).  Closes: #1109803.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sat, 26 Jul 2025 20:29:12 +0200
+
 glibc (2.41-10) unstable; urgency=medium
 
   [ Samuel Thibault ]
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index f8df40b4..ac1e1c31 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -22,10 +22,10 @@ index d0108d2caa..aa547a443f 100644
  $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
  else  # build-static
 diff --git a/NEWS b/NEWS
-index b11422b060..90d090ea77 100644
+index b11422b060..89d0935beb 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,34 @@ See the end for copying conditions.
+@@ -5,6 +5,36 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
@@ -56,6 +56,8 @@ index b11422b060..90d090ea77 100644
 +  [32981] ports: elf/tst-execstack-prog-static-tunable fails on
 +    sparc64-linux-gnu
 +  [32987] elf: Fix subprocess status handling for tst-dlopen-sgid
++  [33164] iconv -o should not create executable files
++  [33185] Fix double-free after allocation failure in regcomp
 +
  Version 2.41
  
@@ -1589,6 +1591,43 @@ index 9f5990f340..8df6f5906e 100644
 +glibc.rtld.execstack: 1 (min: 0, max: 2)
  glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
  glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
+diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
+index 7dba5d8dff..558cfb11a3 100644
+--- a/iconv/iconv_prog.c
++++ b/iconv/iconv_prog.c
+@@ -436,7 +436,7 @@ input_error (const char *path)
+ static void
+ open_output_direct (void)
+ {
+-  output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
++  output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+   if (output_fd < 0)
+     output_error ();
+ }
+@@ -457,7 +457,7 @@ prepare_output_file (char **argv)
+   else
+     {
+       /* If iconv creates the output file, no overlap is possible.  */
+-      output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0777);
++      output_fd = open64 (output_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
+       if (output_fd >= 0)
+ 	output_buffer_size = copy_buffer_size;
+       else
+diff --git a/iconv/tst-iconv_prog-buffer.sh b/iconv/tst-iconv_prog-buffer.sh
+index 1c499d590d..40340c38fa 100644
+--- a/iconv/tst-iconv_prog-buffer.sh
++++ b/iconv/tst-iconv_prog-buffer.sh
+@@ -75,6 +75,10 @@ run_iconv () {
+ }
+ 
+ check_out_expected () {
++    if test -x "$tmp/out" ; then
++	echo "error: iconv output file is executable"
++	failure=true
++    fi
+     if ! cmp -s "$tmp/out" "$tmp/expected" ; then
+         echo "error: iconv output difference" >&$logfd
+         echo "*** expected ***" >&$logfd
 diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in
 index 01ba689aa8..4f194da19d 100644
 --- a/math/auto-libm-test-in
@@ -1797,6 +1836,18 @@ index e98e2df152..43dd16d59c 100644
  			iattr->stacksize = to - (size_t) iattr->stackaddr;
  #endif
  		      /* We succeed and no need to look further.  */
+diff --git a/posix/Makefile b/posix/Makefile
+index a650abf598..0e209a7ed0 100644
+--- a/posix/Makefile
++++ b/posix/Makefile
+@@ -303,6 +303,7 @@ tests := \
+   tst-posix_spawn-setsid \
+   tst-preadwrite \
+   tst-preadwrite64 \
++  tst-regcomp-bracket-free \
+   tst-regcomp-truncated \
+   tst-regex \
+   tst-regex2 \
 diff --git a/posix/environ.c b/posix/environ.c
 index a0ed0d80ea..924effe3cd 100644
 --- a/posix/environ.c
@@ -1816,6 +1867,210 @@ index a0ed0d80ea..924effe3cd 100644
 +
 +struct environ_array *__environ_array_list;
 +environ_counter __environ_counter;
+diff --git a/posix/regcomp.c b/posix/regcomp.c
+index 69675d81f7..5c486cee56 100644
+--- a/posix/regcomp.c
++++ b/posix/regcomp.c
+@@ -3384,6 +3384,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+     {
+ #ifdef RE_ENABLE_I18N
+       free_charset (mbcset);
++      mbcset = NULL;
+ #endif
+       /* Build a tree for simple bracket.  */
+       br_token.type = SIMPLE_BRACKET;
+@@ -3399,7 +3400,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+  parse_bracket_exp_free_return:
+   re_free (sbcset);
+ #ifdef RE_ENABLE_I18N
+-  free_charset (mbcset);
++  if (__glibc_likely (mbcset != NULL))
++    free_charset (mbcset);
+ #endif /* RE_ENABLE_I18N */
+   return NULL;
+ }
+diff --git a/posix/tst-regcomp-bracket-free.c b/posix/tst-regcomp-bracket-free.c
+new file mode 100644
+index 0000000000..3c091d8c44
+--- /dev/null
++++ b/posix/tst-regcomp-bracket-free.c
+@@ -0,0 +1,176 @@
++/* Test regcomp bracket parsing with injected allocation failures (bug 33185).
++   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/>.  */
++
++/* This test invokes regcomp multiple times, failing one memory
++   allocation in each call.  The function call should fail with
++   REG_ESPACE (or succeed if it can recover from the allocation
++   failure).  Previously, there was double-free bug.  */
++
++#include <errno.h>
++#include <regex.h>
++#include <stdio.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++
++/* Data structure allocated via MAP_SHARED, so that writes from the
++   subprocess are visible.  */
++struct shared_data
++{
++  /* Number of tracked allocations performed so far.  */
++  volatile unsigned int allocation_count;
++
++  /* If this number is reached, one allocation fails.  */
++  volatile unsigned int failing_allocation;
++
++  /* The subprocess stores the expected name here.  */
++  char name[100];
++};
++
++/* Allocation count in shared mapping.  */
++static struct shared_data *shared;
++
++/* Returns true if a failure should be injected for this allocation.  */
++static bool
++fail_this_allocation (void)
++{
++  if (shared != NULL)
++    {
++      unsigned int count = shared->allocation_count;
++      shared->allocation_count = count + 1;
++      return count == shared->failing_allocation;
++    }
++  else
++    return false;
++}
++
++/* Failure-injecting wrappers for allocation functions used by glibc.  */
++
++void *
++malloc (size_t size)
++{
++  if (fail_this_allocation ())
++    {
++      errno = ENOMEM;
++      return NULL;
++    }
++  extern __typeof (malloc) __libc_malloc;
++  return __libc_malloc (size);
++}
++
++void *
++calloc (size_t a, size_t b)
++{
++  if (fail_this_allocation ())
++    {
++      errno = ENOMEM;
++      return NULL;
++    }
++  extern __typeof (calloc) __libc_calloc;
++  return __libc_calloc (a, b);
++}
++
++void *
++realloc (void *ptr, size_t size)
++{
++  if (fail_this_allocation ())
++    {
++      errno = ENOMEM;
++      return NULL;
++    }
++  extern __typeof (realloc) __libc_realloc;
++  return __libc_realloc (ptr, size);
++}
++
++/* No-op subprocess to verify that support_isolate_in_subprocess does
++   not perform any heap allocations.  */
++static void
++no_op (void *ignored)
++{
++}
++
++/* Perform a regcomp call in a subprocess.  Used to count its
++   allocations.  */
++static void
++initialize (void *regexp1)
++{
++  const char *regexp = regexp1;
++
++  shared->allocation_count = 0;
++
++  regex_t reg;
++  TEST_COMPARE (regcomp (&reg, regexp, 0), 0);
++}
++
++/* Perform regcomp in a subprocess with fault injection.  */
++static void
++test_in_subprocess (void *regexp1)
++{
++  const char *regexp = regexp1;
++  unsigned int inject_at = shared->failing_allocation;
++
++  regex_t reg;
++  int ret = regcomp (&reg, regexp, 0);
++
++  if (ret != 0)
++    {
++      TEST_COMPARE (ret, REG_ESPACE);
++      printf ("info: allocation %u failure results in return value %d,"
++              " error %s (%d)\n",
++              inject_at, ret, strerrorname_np (errno), errno);
++    }
++}
++
++static int
++do_test (void)
++{
++  char regexp[] = "[:alpha:]";
++
++  shared = support_shared_allocate (sizeof (*shared));
++
++  /* Disable fault injection.  */
++  shared->failing_allocation = ~0U;
++
++  support_isolate_in_subprocess (no_op, NULL);
++  TEST_COMPARE (shared->allocation_count, 0);
++
++  support_isolate_in_subprocess (initialize, regexp);
++
++  /* The number of allocations in the successful case, plus some
++     slack.  Once the number of expected allocations is exceeded,
++     injecting further failures does not make a difference.  */
++  unsigned int maximum_allocation_count = shared->allocation_count;
++  printf ("info: successful call performs %u allocations\n",
++          maximum_allocation_count);
++  maximum_allocation_count += 10;
++
++  for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
++       ++inject_at)
++    {
++      shared->allocation_count = 0;
++      shared->failing_allocation = inject_at;
++      support_isolate_in_subprocess (test_in_subprocess, regexp);
++    }
++
++  support_shared_free (shared);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
 diff --git a/stdlib/Makefile b/stdlib/Makefile
 index 1c4fa2382f..c9c8f702a2 100644
 --- a/stdlib/Makefile

Reply to: