The glob function from glibc makes a recursive call for every trailing
slash character in the given pattern. This makes it easy to run out of
stack space.

The attached patches fix it and add a test in Gnulib. It is based on my
patch in glibc, which is just waiting for a final "Reviewed-by" before
committing [1].

I'm not expecting to need a v3 patch for glibc, but I will hold off
pushing to Gnulib just in case.

Collin

[1] 
https://inbox.sourceware.org/libc-alpha/[email protected]/T/#m9e88071d873191ae84a141823b2e310aabf4e6e2

>From b0334ff2173942d282eb85abd9bb2865286f8184 Mon Sep 17 00:00:00 2001
Message-ID: <b0334ff2173942d282eb85abd9bb2865286f8184.1760161417.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Fri, 10 Oct 2025 22:34:19 -0700
Subject: [PATCH 1/2] glob: Prevent a stack overflow with many trailing
 slashes.

* lib/glob.c (__glob): Strip trailing slashes before making the
recursive call.
* m4/glob.m4 (gl_GLOB): Check for the glibc bug.
* doc/posix-functions/glob.texi: Mention the bug.
---
 ChangeLog                     |  6 +++++
 doc/posix-functions/glob.texi |  5 ++++
 lib/glob.c                    |  4 +++
 m4/glob.m4                    | 50 +++++++++++++++++++++++++++--------
 4 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 07f0503f84..3f1eaf7f24 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2025-10-10  Collin Funk  <[email protected]>
 
+	glob: Prevent a stack overflow with many trailing slashes.
+	* lib/glob.c (__glob): Strip trailing slashes before making the
+	recursive call.
+	* m4/glob.m4 (gl_GLOB): Check for the glibc bug.
+	* doc/posix-functions/glob.texi: Mention the bug.
+
 	getline tests: Add a test for the glibc bug.
 	* tests/test-getline.c (main): Check that the buffer is terminated with
 	a NUL character when the first character read is EOF.
diff --git a/doc/posix-functions/glob.texi b/doc/posix-functions/glob.texi
index c5c423bc1a..705aa1e9d3 100644
--- a/doc/posix-functions/glob.texi
+++ b/doc/posix-functions/glob.texi
@@ -20,6 +20,11 @@ @node glob
 On platforms where @code{off_t} is a 32-bit type, this function may not
 work correctly on huge directories 2 GiB and larger.
 @xref{Large File Support}.
+@item
+This function makes a recursive call for every trailing @code{/}
+character on some platforms, which can cause the stack to overflow:
+@c https://sourceware.org/PR30635
+glibc 2.42.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/lib/glob.c b/lib/glob.c
index 0bd8b4237c..48f10ae0e1 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -582,6 +582,10 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                   flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
                 }
             }
+          /* Prevent stack overflows with many trailing '/' characters.  */
+          for (char *p = &dirname[dirlen - 1];
+               p > dirname && p[0] == '/' && p[-1] == '/'; --p)
+            p[0] = '\0';
           int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob);
           if (val == 0)
             pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
diff --git a/m4/glob.m4 b/m4/glob.m4
index ee0320bb10..1bbe6603ca 100644
--- a/m4/glob.m4
+++ b/m4/glob.m4
@@ -1,5 +1,5 @@
 # glob.m4
-# serial 30
+# serial 31
 dnl Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -23,16 +23,44 @@ AC_DEFUN([gl_GLOB]
     esac
   else
 
-    AC_CACHE_CHECK([for GNU glob interface version 1 or 2],
-      [gl_cv_gnu_glob_interface_version_1_2],
-[     AC_COMPILE_IFELSE([AC_LANG_SOURCE(
-[[#include <gnu-versions.h>
-char a[_GNU_GLOB_INTERFACE_VERSION == 1 || _GNU_GLOB_INTERFACE_VERSION == 2 ? 1 : -1];]])],
-        [gl_cv_gnu_glob_interface_version_1_2=yes],
-        [gl_cv_gnu_glob_interface_version_1_2=no])])
-    if test "$gl_cv_gnu_glob_interface_version_1_2" = "no"; then
-      REPLACE_GLOB=1
-    fi
+    AC_CACHE_CHECK([whether glob overflows the stack with recursive calls],
+      [gl_cv_glob_stack_overflow],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+            #include <stddef.h>
+            #include <stdlib.h>
+            #include <string.h>
+            #include <glob.h>
+            int
+            main (void)
+            {
+              /* Test that glob with many trailing slashes does not overflow
+                 the stack as it did in glibc 2.42 and earlier.  */
+              char *p = malloc (10000);
+              glob_t g;
+              int res;
+              if (p != NULL)
+                {
+                  memset (p, '/', 9999);
+                  p[9999] = '\0';
+                  res = glob (p, 0, NULL, &g);
+                  globfree (&g);
+                }
+              return !(res == 0);
+            }]])],
+         [gl_cv_glob_overflows_stack=no],
+         [gl_cv_glob_overflows_stack=yes],
+         [case "$host_os" in
+                               # Guess yes on glibc systems.
+            *-gnu* | gnu*)     gl_cv_glob_overflows_stack="guessing yes" ;;
+          esac
+         ])
+      ])
+
+    case $gl_cv_glob_overflows_stack in
+        *yes) REPLACE_GLOB=1 ;;
+        *) REPLACE_GLOB=0 ;;
+    esac
 
     if test $REPLACE_GLOB = 0; then
       AC_CACHE_CHECK([whether glob lists broken symlinks],
-- 
2.51.0

>From 0b75106032f73a068ba14ff0a223d4c3312a33ce Mon Sep 17 00:00:00 2001
Message-ID: <0b75106032f73a068ba14ff0a223d4c3312a33ce.1760161418.git.collin.fu...@gmail.com>
In-Reply-To: <b0334ff2173942d282eb85abd9bb2865286f8184.1760161417.git.collin.fu...@gmail.com>
References: <b0334ff2173942d282eb85abd9bb2865286f8184.1760161417.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Fri, 10 Oct 2025 22:36:11 -0700
Subject: [PATCH 2/2] glob tests: Add a test for the glibc bug.

* tests/test-glob.c (main): Call glob with a pattern of all slashes to
check if the stack overflows due to recursive calls.
---
 ChangeLog         |  4 ++++
 tests/test-glob.c | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 3f1eaf7f24..9ce420cb64 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2025-10-10  Collin Funk  <[email protected]>
 
+	glob tests: Add a test for the glibc bug.
+	* tests/test-glob.c (main): Call glob with a pattern of all slashes to
+	check if the stack overflows due to recursive calls.
+
 	glob: Prevent a stack overflow with many trailing slashes.
 	* lib/glob.c (__glob): Strip trailing slashes before making the
 	recursive call.
diff --git a/tests/test-glob.c b/tests/test-glob.c
index b064e37b40..52ba191b74 100644
--- a/tests/test-glob.c
+++ b/tests/test-glob.c
@@ -95,5 +95,17 @@ main ()
       globfree (&g);
     }
 
+  /* Test that glob with many trailing slashes does not overflow the
+     stack as it did in glibc 2.42 and earlier.  */
+  char *p = malloc (10000);
+  if (p != NULL)
+    {
+      memset (p, '/', 9999);
+      p[9999] = '\0';
+      res = glob (p, 0, NULL, &g);
+      ASSERT (res == 0);
+      globfree (&g);
+    }
+
   return test_exit_status;
 }
-- 
2.51.0

Reply via email to