]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/fs-util: prefer fchmodat2 in fchmod_opath
authorArseny Maslennikov <arseny@altlinux.org>
Sat, 21 Oct 2023 08:00:00 +0000 (11:00 +0300)
committerMike Yuan <me@yhndnzj.com>
Wed, 1 Nov 2023 16:26:22 +0000 (00:26 +0800)
Co-authored-by: Mike Yuan <me@yhndnzj.com>
src/basic/fs-util.c

index a9336f1a67587dccd14de607b23498aab9d51031..f5a1a8edbf17c1584178b1e78275f4efacfea02f 100644 (file)
@@ -288,8 +288,22 @@ int fchmod_umask(int fd, mode_t m) {
 
 int fchmod_opath(int fd, mode_t m) {
         /* This function operates also on fd that might have been opened with
-         * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
-         * fchownat() does. */
+         * O_PATH. The tool set we have is non-intuitive:
+         * - fchmod(2) only operates on open files (i. e., fds with an open file description);
+         * - fchmodat(2) does not have a flag arg like fchownat(2) does, so no way to pass AT_EMPTY_PATH;
+         *   + it should not be confused with the libc fchmodat(3) interface, which adds 4th flag argument,
+         *     but does not support AT_EMPTY_PATH (only supports AT_SYMLINK_NOFOLLOW);
+         * - fchmodat2(2) supports all the AT_* flags, but is still very recent.
+         *
+         * We try to use fchmodat2(), and, if it is not supported, resort
+         * to the /proc/self/fd dance. */
+
+        assert(fd >= 0);
+
+        if (fchmodat2(fd, "", m, AT_EMPTY_PATH) >= 0)
+                return 0;
+        if (!IN_SET(errno, ENOSYS, EPERM)) /* Some container managers block unknown syscalls with EPERM */
+                return -errno;
 
         if (chmod(FORMAT_PROC_FD_PATH(fd), m) < 0) {
                 if (errno != ENOENT)