@@ -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);
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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 */
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -117,6 +117,7 @@ fanotify_mark
fchdir
fchmod
fchmodat
+fchmodat2
fchown
fchown32
fchownat
@@ -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
@@ -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