[libc-commits] [libc] c53000a - [libc] Reject unsupported flags in fchmodat with ENOTSUP (#223165)

via libc-commits libc-commits at lists.llvm.org
Wed Sep 16 01:47:23 PDT 2026


Author: Aman Maurya
Date: 2026-09-16T10:47:17+02:00
New Revision: c53000a7282bedb125ffaab8cb072df85596d095

URL: https://github.com/llvm/llvm-project/commit/c53000a7282bedb125ffaab8cb072df85596d095
DIFF: https://github.com/llvm/llvm-project/commit/c53000a7282bedb125ffaab8cb072df85596d095.diff

LOG: [libc] Reject unsupported flags in fchmodat with ENOTSUP (#223165)

### Summary
The Linux kernel's `SYS_fchmodat` system call only takes 3 arguments
(`dirfd`, `pathname`, `mode`), but our syscall wrapper was passing a 4th
`flags` argument that the kernel simply dropped.

This PR cleans up the wrapper to pass the 3 arguments expected by the
kernel, and adds a check to `fchmodat` to return `-1` with `ENOTSUP`
whenever non-zero flags (like `AT_SYMLINK_NOFOLLOW`) are passed.

Fixes #223072

### Changes
- Cleaned up `linux_syscalls::fchmodat` to pass only 3 arguments to
`SYS_fchmodat`.
- Added a check in `fchmodat` entrypoint to set `libc_errno = ENOTSUP`
and return `-1` if `flags != 0`.
- Added `libc.hdr.errno_macros` to the CMake dependencies for `fchmodat`
and its unit test.
- Added tests in `fchmodat_test.cpp` to verify that passing non-zero
flags fails with `ENOTSUP`.

### Testing
- Ran `clang-format` on touched files.
- Built and ran hermetic tests: `libc.test.src.sys.stat.fchmodat_test`
(all 3 tests pass: `ChangeAndOpen`, `NonExistentFile`,
`UnsupportedFlags`).

Added: 
    

Modified: 
    libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
    libc/src/sys/stat/linux/CMakeLists.txt
    libc/src/sys/stat/linux/fchmodat.cpp
    libc/test/src/sys/stat/CMakeLists.txt
    libc/test/src/sys/stat/fchmodat_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
index 7b8ee1a079b99..b62a040e9fe54 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h
@@ -24,9 +24,8 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace linux_syscalls {
 
-LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode,
-                                  int flags) {
-  int ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode, flags);
+LIBC_INLINE ErrorOr<int> fchmodat(int fd, const char *path, mode_t mode) {
+  int ret = syscall_impl<int>(SYS_fchmodat, fd, path, mode);
   if (ret < 0)
     return Error(-ret);
   return ret;

diff  --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt
index b087fc927459c..b35cd11ea8da5 100644
--- a/libc/src/sys/stat/linux/CMakeLists.txt
+++ b/libc/src/sys/stat/linux/CMakeLists.txt
@@ -30,6 +30,7 @@ add_entrypoint_object(
   HDRS
     ../fchmodat.h
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.types.mode_t
     libc.src.__support.OSUtil.linux.syscall_wrappers.fchmodat
     libc.src.errno.errno

diff  --git a/libc/src/sys/stat/linux/fchmodat.cpp b/libc/src/sys/stat/linux/fchmodat.cpp
index 38e02b5d61617..29bee319ed0ad 100644
--- a/libc/src/sys/stat/linux/fchmodat.cpp
+++ b/libc/src/sys/stat/linux/fchmodat.cpp
@@ -8,6 +8,7 @@
 
 #include "src/sys/stat/fchmodat.h"
 
+#include "hdr/errno_macros.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/fchmodat.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
@@ -17,7 +18,11 @@ namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, fchmodat,
                    (int dirfd, const char *path, mode_t mode, int flags)) {
-  auto result = linux_syscalls::fchmodat(dirfd, path, mode, flags);
+  if (flags != 0) {
+    libc_errno = ENOTSUP;
+    return -1;
+  }
+  auto result = linux_syscalls::fchmodat(dirfd, path, mode);
   if (!result) {
     libc_errno = result.error();
     return -1;

diff  --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt
index 32ce8f50c0ef1..775348f8c18fa 100644
--- a/libc/test/src/sys/stat/CMakeLists.txt
+++ b/libc/test/src/sys/stat/CMakeLists.txt
@@ -28,6 +28,7 @@ add_libc_test(
   SRCS
     fchmodat_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.fcntl_macros
     libc.hdr.sys_stat_macros
     libc.hdr.types.struct_stat

diff  --git a/libc/test/src/sys/stat/fchmodat_test.cpp b/libc/test/src/sys/stat/fchmodat_test.cpp
index 8a1a9379aca71..868cdb2bc817a 100644
--- a/libc/test/src/sys/stat/fchmodat_test.cpp
+++ b/libc/test/src/sys/stat/fchmodat_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
 #include "hdr/fcntl_macros.h"
 #include "hdr/sys_stat_macros.h"
 #include "hdr/types/struct_stat.h"
@@ -65,3 +66,12 @@ TEST_F(LlvmLibcFchmodatTest, NonExistentFile) {
       LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR, 0),
       Fails(ENOENT));
 }
+
+TEST_F(LlvmLibcFchmodatTest, UnsupportedFlags) {
+  ASSERT_THAT(LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR,
+                                       AT_SYMLINK_NOFOLLOW),
+              Fails(ENOTSUP));
+  ASSERT_THAT(
+      LIBC_NAMESPACE::fchmodat(AT_FDCWD, "non-existent-file", S_IRUSR, -1),
+      Fails(ENOTSUP));
+}


        


More information about the libc-commits mailing list