On 14/11/2026 05:23, Collin Funk wrote:
Pádraig Brady <[email protected]> writes:

The first patch fixes chmod to now correctly diagnose
its failure to work with any files on Linux <= 6.5
when /proc is not available (like e.g. in a chroot).
Otherwise it would silently do nothing, ignoring all
the ENOTSUPs it was getting.

I'm a bit surprised we didn't get any reports for that,
but I suppose Linux 6.6 was released in 2023 and
coreutils 9.5 was released in 2024, so there wouldn't
have been huge overlap of this issue.

The second patch adds the racy fallback (without AT_SYMLINK_NOFOLLOW),
to allow chmod to work on older systems without /proc.
However I'm 60:40 against applying that one because:
  1. The problematic kernels are over 3 years old now
     and we did get no reports after all.
  2. It should be easy enough to mount /proc to avoid the issue
  3. The fallback is TOCTOU racy.

Speaking generally, I think it is nice to support old systems when
possible. Even if it involves an implementation with races. In many
cases, Gnulib fallbacks have races because the operating system does not
provide adequate functionality to avoid them.

I see that the current oldest LTS kernel is 5.10.274, which I assume
would be affected by this issue [1]. Granted, I assume those releases
are mostly used by distributors, e.g., Red Hat, which will provide
various other patches and a coreutils version from around the time of
5.10's initial release. Going out of their way to build the latest
coreutils release would be strange.

The first patch looks good for certain, though. If someone actually ran
into it, I could see it causing a lot of confusion.

Collin

[1] https://www.kernel.org/

Actually I see gnulib already has this fallback in place for older systems.
It gets a bit complicated with glibc and kernel version combos,
but assuming /proc is available at configure time, and no configure overrides:

glibc          Linux kernel  Implementation selected    Without /proc
=============  ============  ========================  ======================
≤ 2.31         Any           gnulib /proc emulation     Racy fallback
-------------  ------------  ------------------------  ----------------------
2.32–2.38      Any           glibc /proc emulation      Fails with ENOTSUP
-------------  ------------  ------------------------  ----------------------
≥ 2.39         < 6.6         glibc /proc emulation      Fails with ENOTSUP
-------------  ------------  ------------------------  ----------------------
≥ 2.39         ≥ 6.6         glibc fchmodat2            Native operation

In other words Debian 12, or Fedora 33-39 without /proc can fail with ENOTSUP.
Debian 13 was released Aug 2025, and Fedora 40 Apr 2024.

So the main problematic combo here I think is,
Debian 12 + coreutils ≥ 9.5 + unavailable /proc.
Now I'm still not inclined to add the fallback in chmod.c,
mainly as other utils would also need to do the same for consistency.

One can force the gnulib replacement (with fallback) using
  ./configure gl_cv_func_fchmodat_works=no
so one thing we could do is to maybe change gnulib
to set gl_cv_func_fchmodat_works=no for glibc < 2.39,
so you'd have slightly bigger binaries on older glibc,
but you'd have the fallback on these older systems (without /proc).

Given https://popcon.debian.org/ shows Debian 12 is still quite common,
I'm 70:30 for applying the attached gnulib patch to do this.
I tested on Debian 12 with the following wrapper to hide /proc,
and it worked as expected.

chmod() {
  unshare -rm sh -c \
    "mount -t tmpfs tmpfs /proc && env chmod \"\$@\"" -- "$@";
}

cheers,
Padraig
From cdde38565f92cf62eeb253fc110f683ebf36c7ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Sat, 14 Nov 2026 14:48:58 +0000
Subject: [PATCH] fchmodat: require AT_SYMLINK_NOFOLLOW emulation on glibc
 2.32-2.38

* m4/fchmodat.m4: Use our fallback which tries AT_SYMLINK_NOFOLLOW
on non-symlinks when /proc is not mounted, as the glibc /proc
emulation in these versions has no fallback.
---
 ChangeLog      |  7 +++++++
 m4/fchmodat.m4 | 10 +++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 13c42cc886..88c7ce950a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2026-11-14  Pádraig Brady  <[email protected]>
+
+	fchmodat: require AT_SYMLINK_NOFOLLOW emulation on glibc 2.32-2.38
+	* m4/fchmodat.m4: Use our fallback which tries AT_SYMLINK_NOFOLLOW
+	on non-symlinks when /proc is not mounted, as the glibc /proc
+	emulation in these versions has no fallback.
+
 2026-11-12  Collin Funk  <[email protected]>
 
 	fts: Sync from glibc.
diff --git a/m4/fchmodat.m4 b/m4/fchmodat.m4
index e468870806..ab74e098fb 100644
--- a/m4/fchmodat.m4
+++ b/m4/fchmodat.m4
@@ -1,5 +1,5 @@
 # fchmodat.m4
-# serial 9
+# serial 10
 dnl Copyright (C) 2004-2026 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -56,7 +56,15 @@ AC_DEFUN([gl_FUNC_FCHMODAT],
               /* Test whether fchmodat+AT_SYMLINK_NOFOLLOW works on non-symlinks.
                  This test fails on GNU/Linux with glibc 2.31 (but not on
                  GNU/kFreeBSD nor GNU/Hurd) and Cygwin 2.9.  */
+              /* On Linux, glibc 2.32 - 2.38 accepts this flag and
+                 emulates it using /proc, but does not have a fallback
+                 like gnulib does where /proc is not available.  */
+              #if defined __linux__ && defined __GLIBC__ \
+                  && __GLIBC__ == 2 && __GLIBC_MINOR__ < 39
+              if (1)
+              #else
               if (fchmodat (AT_FDCWD, file, desired, AT_SYMLINK_NOFOLLOW) != 0)
+              #endif
                 result |= 4;
               if (stat (file, &st) != 0)
                 return 1;
-- 
2.56.0

Reply via email to