diff mbox series

[RFC] linux: Use fchmodat2 on fchmod for flags different than 0 (BZ 26401)

Message ID 20230928165621.372548-1-adhemerval.zanella@linaro.org
State New
Headers show
Series [RFC] linux: Use fchmodat2 on fchmod for flags different than 0 (BZ 26401) | expand

Commit Message

Adhemerval Zanella Sept. 28, 2023, 4:56 p.m. UTC
Linux 6.6 (09da082b07bbae1c) added support for fchmodat2, which is
has similar semantic of fchmodat with an extra flag argument.  This
allow fchmodat to implement AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH
without the need to procfs.

The syscall is registered on all architectures (with value of 452
except on alpha which is 562, commit 78252deb023cf087).

Checked on x86_64-linux-gnu on a 6.6 kernel.

PS: setting it as RFC because there is no Linux 6.6 release yet.

---
 io/tst-lchmod.c                               |   4 +-
 .../unix/sysv/linux/aarch64/arch-syscall.h    |   1 +
 sysdeps/unix/sysv/linux/alpha/arch-syscall.h  |   1 +
 sysdeps/unix/sysv/linux/arc/arch-syscall.h    |   1 +
 sysdeps/unix/sysv/linux/arm/arch-syscall.h    |   1 +
 sysdeps/unix/sysv/linux/csky/arch-syscall.h   |   1 +
 sysdeps/unix/sysv/linux/fchmodat.c            | 120 ++++++++++--------
 sysdeps/unix/sysv/linux/hppa/arch-syscall.h   |   1 +
 sysdeps/unix/sysv/linux/i386/arch-syscall.h   |   1 +
 sysdeps/unix/sysv/linux/ia64/arch-syscall.h   |   1 +
 sysdeps/unix/sysv/linux/kernel-features.h     |   8 ++
 .../unix/sysv/linux/loongarch/arch-syscall.h  |   1 +
 sysdeps/unix/sysv/linux/m68k/arch-syscall.h   |   1 +
 .../unix/sysv/linux/microblaze/arch-syscall.h |   1 +
 .../sysv/linux/mips/mips32/arch-syscall.h     |   1 +
 .../sysv/linux/mips/mips64/n32/arch-syscall.h |   1 +
 .../sysv/linux/mips/mips64/n64/arch-syscall.h |   1 +
 sysdeps/unix/sysv/linux/nios2/arch-syscall.h  |   1 +
 sysdeps/unix/sysv/linux/or1k/arch-syscall.h   |   1 +
 .../linux/powerpc/powerpc32/arch-syscall.h    |   1 +
 .../linux/powerpc/powerpc64/arch-syscall.h    |   1 +
 .../unix/sysv/linux/riscv/rv32/arch-syscall.h |   1 +
 .../unix/sysv/linux/riscv/rv64/arch-syscall.h |   1 +
 .../sysv/linux/s390/s390-32/arch-syscall.h    |   1 +
 .../sysv/linux/s390/s390-64/arch-syscall.h    |   1 +
 sysdeps/unix/sysv/linux/sh/arch-syscall.h     |   1 +
 .../sysv/linux/sparc/sparc32/arch-syscall.h   |   1 +
 .../sysv/linux/sparc/sparc64/arch-syscall.h   |   1 +
 sysdeps/unix/sysv/linux/syscall-names.list    |   1 +
 .../unix/sysv/linux/x86_64/64/arch-syscall.h  |   1 +
 .../unix/sysv/linux/x86_64/x32/arch-syscall.h |   1 +
 31 files changed, 105 insertions(+), 55 deletions(-)

Comments

Florian Weimer Sept. 29, 2023, 10:43 a.m. UTC | #1
* Adhemerval Zanella:

> Linux 6.6 (09da082b07bbae1c) added support for fchmodat2, which is
> has similar semantic of fchmodat with an extra flag argument.  This
> allow fchmodat to implement AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH
> without the need to procfs.
>
> The syscall is registered on all architectures (with value of 452
> except on alpha which is 562, commit 78252deb023cf087).
>
> Checked on x86_64-linux-gnu on a 6.6 kernel.
>
> PS: setting it as RFC because there is no Linux 6.6 release yet.

Thanks for getting the work here started.

The syscall list update should definitely be in a separate commit.

> diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c
> index 99527a3727..99d3df6440 100644
> --- a/sysdeps/unix/sysv/linux/fchmodat.c
> +++ b/sysdeps/unix/sysv/linux/fchmodat.c
> @@ -26,66 +26,80 @@
>  #include <sysdep.h>
>  #include <unistd.h>

diff -w makes the diff more manageable.

> +  /* The kernel system call does not have a mode argument.
> +     However, we can create an O_PATH descriptor and change that
> +     via /proc (which does not resolve symbolic links).  */

I would update the comment to mention the old fchmodat system call
explicitly.

The mechanics look okay to me.

I wonder how much breakage we are going to see due to EPERM instead of
ENOSYS on broken container runtimes.  We can certainly try to get the
world cleaned up for the glibc 2.39 release, we still have some time.

Thanks,
Florian
Adhemerval Zanella Oct. 2, 2023, 12:56 p.m. UTC | #2
On 29/09/23 07:43, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> Linux 6.6 (09da082b07bbae1c) added support for fchmodat2, which is
>> has similar semantic of fchmodat with an extra flag argument.  This
>> allow fchmodat to implement AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH
>> without the need to procfs.
>>
>> The syscall is registered on all architectures (with value of 452
>> except on alpha which is 562, commit 78252deb023cf087).
>>
>> Checked on x86_64-linux-gnu on a 6.6 kernel.
>>
>> PS: setting it as RFC because there is no Linux 6.6 release yet.
> 
> Thanks for getting the work here started.
> 
> The syscall list update should definitely be in a separate commit.

It is usually done once the kernel is actually release, it does
make sense to be in a different commit. 

> 
>> diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c
>> index 99527a3727..99d3df6440 100644
>> --- a/sysdeps/unix/sysv/linux/fchmodat.c
>> +++ b/sysdeps/unix/sysv/linux/fchmodat.c
>> @@ -26,66 +26,80 @@
>>  #include <sysdep.h>
>>  #include <unistd.h>
> 
> diff -w makes the diff more manageable.
> 
>> +  /* The kernel system call does not have a mode argument.
>> +     However, we can create an O_PATH descriptor and change that
>> +     via /proc (which does not resolve symbolic links).  */
> 
> I would update the comment to mention the old fchmodat system call
> explicitly.
> 
> The mechanics look okay to me.
> 
> I wonder how much breakage we are going to see due to EPERM instead of
> ENOSYS on broken container runtimes.  We can certainly try to get the
> world cleaned up for the glibc 2.39 release, we still have some time.

We still see some, the armhf buildbot does same the this very issue.
diff mbox series

Patch

diff --git a/io/tst-lchmod.c b/io/tst-lchmod.c
index 2bf4835b05..6496dc61e0 100644
--- a/io/tst-lchmod.c
+++ b/io/tst-lchmod.c
@@ -219,9 +219,9 @@  test_1 (bool do_relative_path, int (*chmod_func) (int fd, const char *, mode_t,
          /* The error code from the openat fallback leaks out.  */
          if (errno != ENFILE && errno != EMFILE)
            TEST_COMPARE (errno, EOPNOTSUPP);
+	 xstat (path_file, &st);
+	 TEST_COMPARE (st.st_mode & 0777, 3);
        }
-     xstat (path_file, &st);
-     TEST_COMPARE (st.st_mode & 0777, 3);
 
      /* Close the descriptors.  */
      for (int *pfd = fd_list_begin (&fd_list); pfd < fd_list_end (&fd_list);
diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
index 8f21ee66a0..746991aa2f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
@@ -44,6 +44,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl 25
diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
index c5802a5fec..32efe51267 100644
--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
@@ -56,6 +56,7 @@ 
 #define __NR_fchdir 13
 #define __NR_fchmod 124
 #define __NR_fchmodat 461
+#define __NR_fchmodat2 562
 #define __NR_fchown 123
 #define __NR_fchownat 453
 #define __NR_fcntl 92
diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
index f23f9e1154..1d2879e877 100644
--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
@@ -48,6 +48,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl64 25
diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
index 7edf574899..6711981e78 100644
--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
@@ -64,6 +64,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 333
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 325
diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
index d74a06e063..92d9a703ea 100644
--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
@@ -50,6 +50,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl64 25
diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c
index 99527a3727..99d3df6440 100644
--- a/sysdeps/unix/sysv/linux/fchmodat.c
+++ b/sysdeps/unix/sysv/linux/fchmodat.c
@@ -26,66 +26,80 @@ 
 #include <sysdep.h>
 #include <unistd.h>
 
-int
-fchmodat (int fd, const char *file, mode_t mode, int flag)
+#if !__ASSUME_FCHMODAT2
+static int
+fchmodat_fallback (int fd, const char *file, mode_t mode, int flag)
 {
-  if (flag == 0)
-    return INLINE_SYSCALL (fchmodat, 3, fd, file, mode);
-  else if (flag != AT_SYMLINK_NOFOLLOW)
+  if (flag != AT_SYMLINK_NOFOLLOW)
     return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
-  else
-    {
-      /* The kernel system call does not have a mode argument.
-	 However, we can create an O_PATH descriptor and change that
-	 via /proc (which does not resolve symbolic links).  */
 
-      int pathfd = __openat_nocancel (fd, file,
-				      O_PATH | O_NOFOLLOW | O_CLOEXEC);
-      if (pathfd < 0)
-	/* This may report errors such as ENFILE and EMFILE.  The
-	   caller can treat them as temporary if necessary.  */
-	return pathfd;
+  /* The kernel system call does not have a mode argument.
+     However, we can create an O_PATH descriptor and change that
+     via /proc (which does not resolve symbolic links).  */
 
-      /* Use fstatat because fstat does not work on O_PATH descriptors
-	 before Linux 3.6.  */
-      struct __stat64_t64 st;
-      if (__fstatat64_time64 (pathfd, "", &st, AT_EMPTY_PATH) != 0)
-	{
-	  __close_nocancel (pathfd);
-	  return -1;
-	}
+  int pathfd = __openat_nocancel (fd, file,
+				  O_PATH | O_NOFOLLOW | O_CLOEXEC);
+  if (pathfd < 0)
+    /* This may report errors such as ENFILE and EMFILE.  The
+       caller can treat them as temporary if necessary.  */
+    return pathfd;
 
-      /* Some Linux versions with some file systems can actually
-	 change symbolic link permissions via /proc, but this is not
-	 intentional, and it gives inconsistent results (e.g., error
-	 return despite mode change).  The expected behavior is that
-	 symbolic link modes cannot be changed at all, and this check
-	 enforces that.  */
-      if (S_ISLNK (st.st_mode))
-	{
-	  __close_nocancel (pathfd);
-	  __set_errno (EOPNOTSUPP);
-	  return -1;
-	}
+  /* Use fstatat because fstat does not work on O_PATH descriptors
+     before Linux 3.6.  */
+  struct __stat64_t64 st;
+  if (__fstatat64_time64 (pathfd, "", &st, AT_EMPTY_PATH) != 0)
+    {
+      __close_nocancel (pathfd);
+      return -1;
+    }
 
-      /* For most file systems, fchmod does not operate on O_PATH
-	 descriptors, so go through /proc.  */
-      struct fd_to_filename filename;
-      int ret = __chmod (__fd_to_filename (pathfd, &filename), mode);
-      if (ret != 0)
-	{
-	  if (errno == ENOENT)
-	    /* /proc has not been mounted.  Without /proc, there is no
-	       way to upgrade the O_PATH descriptor to a full
-	       descriptor.  It is also not possible to re-open the
-	       file without O_PATH because the file name may refer to
-	       another file, and opening that without O_PATH may have
-	       side effects (such as blocking, device rewinding, or
-	       releasing POSIX locks).  */
-	    __set_errno (EOPNOTSUPP);
-	}
+  /* Some Linux versions with some file systems can actually
+     change symbolic link permissions via /proc, but this is not
+     intentional, and it gives inconsistent results (e.g., error
+     return despite mode change).  The expected behavior is that
+     symbolic link modes cannot be changed at all, and this check
+     enforces that.  */
+  if (S_ISLNK (st.st_mode))
+    {
       __close_nocancel (pathfd);
-      return ret;
+      __set_errno (EOPNOTSUPP);
+      return -1;
+    }
+
+  /* For most file systems, fchmod does not operate on O_PATH
+     descriptors, so go through /proc.  */
+  struct fd_to_filename filename;
+  int ret = __chmod (__fd_to_filename (pathfd, &filename), mode);
+  if (ret != 0)
+    {
+      if (errno == ENOENT)
+	/* /proc has not been mounted.  Without /proc, there is no
+	   way to upgrade the O_PATH descriptor to a full
+	   descriptor.  It is also not possible to re-open the
+	   file without O_PATH because the file name may refer to
+	   another file, and opening that without O_PATH may have
+	   side effects (such as blocking, device rewinding, or
+	   releasing POSIX locks).  */
+	__set_errno (EOPNOTSUPP);
     }
+  __close_nocancel (pathfd);
+  return ret;
+}
+#endif
+
+int
+fchmodat (int fd, const char *file, mode_t mode, int flag)
+{
+#if __ASSUME_FCHMODAT2
+  return INLINE_SYSCALL_CALL (fchmodat2, fd, file, mode, flag);
+#else
+  if (flag == 0)
+    return INLINE_SYSCALL_CALL (fchmodat, fd, file, mode);
+
+  int r = INLINE_SYSCALL_CALL (fchmodat2, fd, file, mode, flag);
+  if (r != 0 && errno == ENOSYS)
+    return fchmodat_fallback (fd, file, mode, flag);
+  return r;
+#endif
 }
 libc_hidden_def (fchmodat)
diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
index 5568b94cd3..fbac124b70 100644
--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
@@ -63,6 +63,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 286
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchownat 278
 #define __NR_fcntl 55
diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
index 3af21a15cb..8961788a96 100644
--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
@@ -67,6 +67,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 306
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 298
diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
index 39b270e642..d11d3a9e63 100644
--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
@@ -55,6 +55,7 @@ 
 #define __NR_fchdir 1035
 #define __NR_fchmod 1099
 #define __NR_fchmodat 1292
+#define __NR_fchmodat2 452
 #define __NR_fchown 1100
 #define __NR_fchownat 1284
 #define __NR_fcntl 1066
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index 07b440f4ee..670d2604d2 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -252,4 +252,12 @@ 
 # define __ASSUME_CLONE3 0
 #endif
 
+/* The fchmodat2 system call was introduced across all architectures
+   in Linux 6.6.  */
+#if __LINUX_KERNEL_VERSION >= 0x060600
+# define __ASSUME_FCHMODAT2 1
+#else
+# define __ASSUME_FCHMODAT2 0
+#endif
+
 #endif /* kernel-features.h */
diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h
index fdefe8bb6f..3664e6f7c8 100644
--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h
@@ -44,6 +44,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl 25
diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
index 315e49cd33..2053d5d392 100644
--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
@@ -67,6 +67,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 299
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 291
diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
index 54af12780c..6865b1693c 100644
--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
@@ -67,6 +67,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 306
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 298
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
index a2aa1ffa1b..b13ace8e1c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
@@ -67,6 +67,7 @@ 
 #define __NR_fchdir 4133
 #define __NR_fchmod 4094
 #define __NR_fchmodat 4299
+#define __NR_fchmodat2 4452
 #define __NR_fchown 4095
 #define __NR_fchownat 4291
 #define __NR_fcntl 4055
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
index 5bec858040..b7a7c0dfa7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
@@ -64,6 +64,7 @@ 
 #define __NR_fchdir 6079
 #define __NR_fchmod 6089
 #define __NR_fchmodat 6262
+#define __NR_fchmodat2 6452
 #define __NR_fchown 6091
 #define __NR_fchownat 6254
 #define __NR_fcntl 6070
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
index 0166371ee2..e5d7f91f48 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
@@ -59,6 +59,7 @@ 
 #define __NR_fchdir 5079
 #define __NR_fchmod 5089
 #define __NR_fchmodat 5258
+#define __NR_fchmodat2 5452
 #define __NR_fchown 5091
 #define __NR_fchownat 5250
 #define __NR_fcntl 5070
diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
index 29a4cfa988..89950cc33a 100644
--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
@@ -49,6 +49,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl64 25
diff --git a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h
index f5a3729663..4c07d9c204 100644
--- a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h
@@ -49,6 +49,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl64 25
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
index 3a212a0269..64683bcb76 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
@@ -66,6 +66,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 297
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchownat 289
 #define __NR_fcntl 55
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
index 1038ead227..af1bbf32e8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
@@ -60,6 +60,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 297
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchownat 289
 #define __NR_fcntl 55
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
index 57b043ffb5..56e3088cbf 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
@@ -43,6 +43,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl64 25
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
index 1041a0f8c9..508161b47a 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
@@ -44,6 +44,7 @@ 
 #define __NR_fchdir 50
 #define __NR_fchmod 52
 #define __NR_fchmodat 53
+#define __NR_fchmodat2 452
 #define __NR_fchown 55
 #define __NR_fchownat 54
 #define __NR_fcntl 25
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
index 70d4c6782e..1498ebf42e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
@@ -65,6 +65,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 299
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 291
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
index 65a8a9e316..624d71b56d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
@@ -56,6 +56,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 299
+#define __NR_fchmodat2 452
 #define __NR_fchown 207
 #define __NR_fchownat 291
 #define __NR_fcntl 55
diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
index 94aad0f119..37211f5f8c 100644
--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
@@ -64,6 +64,7 @@ 
 #define __NR_fchdir 133
 #define __NR_fchmod 94
 #define __NR_fchmodat 306
+#define __NR_fchmodat2 452
 #define __NR_fchown 95
 #define __NR_fchown32 207
 #define __NR_fchownat 298
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
index d630306c75..8093abcc9c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
@@ -66,6 +66,7 @@ 
 #define __NR_fchdir 176
 #define __NR_fchmod 124
 #define __NR_fchmodat 295
+#define __NR_fchmodat2 452
 #define __NR_fchown 123
 #define __NR_fchown32 32
 #define __NR_fchownat 287
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
index 930f29b4d2..d25ccfb571 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
@@ -60,6 +60,7 @@ 
 #define __NR_fchdir 176
 #define __NR_fchmod 124
 #define __NR_fchmodat 295
+#define __NR_fchmodat2 452
 #define __NR_fchown 123
 #define __NR_fchownat 287
 #define __NR_fcntl 92
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
index cf6f70ecd9..e478037b74 100644
--- a/sysdeps/unix/sysv/linux/syscall-names.list
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
@@ -117,6 +117,7 @@  fanotify_mark
 fchdir
 fchmod
 fchmodat
+fchmodat2
 fchown
 fchown32
 fchownat
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
index 58646cf0bd..de6e6323a4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
@@ -59,6 +59,7 @@ 
 #define __NR_fchdir 81
 #define __NR_fchmod 91
 #define __NR_fchmodat 268
+#define __NR_fchmodat2 452
 #define __NR_fchown 93
 #define __NR_fchownat 260
 #define __NR_fcntl 72
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
index 604bcdfa5b..dd5e196272 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -55,6 +55,7 @@ 
 #define __NR_fchdir 1073741905
 #define __NR_fchmod 1073741915
 #define __NR_fchmodat 1073742092
+#define __NR_fchmodat2 1073742276
 #define __NR_fchown 1073741917
 #define __NR_fchownat 1073742084
 #define __NR_fcntl 1073741896