diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-06-15 15:57:18 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-07-08 10:22:34 +0200 |
commit | 427c934fdb634cde4d4426a13e7fc91d99f7db64 (patch) | |
tree | 2ac4e73a518b83f722831c3ceee03f892db763f6 /src/basic/fs-util.c | |
parent | hostnamed: correct variable with errno in fallback_chassis (diff) | |
download | systemd-427c934fdb634cde4d4426a13e7fc91d99f7db64.tar.xz systemd-427c934fdb634cde4d4426a13e7fc91d99f7db64.zip |
fs-util: make sure fsync_directory_of_file() does something useful on O_PATH fds
When handling O_PATH fds it's safe to use the parent of
/proc/self/fd/<fd> for any kind of inode. Hence do so.
Diffstat (limited to 'src/basic/fs-util.c')
-rw-r--r-- | src/basic/fs-util.c | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 8f0834fe46..127f709cd9 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1378,18 +1378,39 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { } int fsync_directory_of_file(int fd) { - _cleanup_free_ char *path = NULL; _cleanup_close_ int dfd = -1; struct stat st; int r; assert(fd >= 0); - /* We only reasonably can do this for regular files and directories, hence check for that */ + /* We only reasonably can do this for regular files and directories, or for O_PATH fds, hence check + * for the inode type first */ if (fstat(fd, &st) < 0) return -errno; - if (S_ISREG(st.st_mode)) { + if (S_ISDIR(st.st_mode)) { + dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0); + if (dfd < 0) + return -errno; + + } else if (!S_ISREG(st.st_mode)) { /* Regular files are OK regardless if O_PATH or not, for all other + * types check O_PATH flag */ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; + + if (!FLAGS_SET(flags, O_PATH)) /* If O_PATH this refers to the inode in the fs, in which case + * we can sensibly do what is requested. Otherwise this refers + * to a socket, fifo or device node, where the concept of a + * containing directory doesn't make too much sense. */ + return -ENOTTY; + } + + if (dfd < 0) { + _cleanup_free_ char *path = NULL; r = fd_get_path(fd, &path); if (r < 0) { @@ -1412,13 +1433,7 @@ int fsync_directory_of_file(int fd) { dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0); if (dfd < 0) return dfd; - - } else if (S_ISDIR(st.st_mode)) { - dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0); - if (dfd < 0) - return -errno; - } else - return -ENOTTY; + } if (fsync(dfd) < 0) return -errno; |