From adecfb3bc0be0def49433277fcad5333893756cc Mon Sep 17 00:00:00 2001 From: Arseny Maslennikov Date: Sat, 21 Oct 2023 11:00:00 +0300 Subject: [PATCH] basic/fs-util: prefer fchmodat2 in fchmod_opath Co-authored-by: Mike Yuan --- src/basic/fs-util.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index a9336f1a67..f5a1a8edbf 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -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) -- 2.25.1