summaryrefslogtreecommitdiff
path: root/src/libnm-systemd-shared/src/basic/fs-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-systemd-shared/src/basic/fs-util.c')
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c183
1 files changed, 80 insertions, 103 deletions
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 5fe8fbab98..28c7247e05 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -8,7 +8,6 @@
#include <unistd.h>
#include "alloc-util.h"
-#include "blockdev-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -581,8 +580,6 @@ int get_files_in_directory(const char *path, char ***list) {
return -errno;
FOREACH_DIRENT_ALL(de, d, return -errno) {
- dirent_ensure_type(d, de);
-
if (!dirent_is_file(de))
continue;
@@ -745,7 +742,8 @@ bool unsafe_transition(const struct stat *a, const struct stat *b) {
}
static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
- _cleanup_free_ char *n1 = NULL, *n2 = NULL;
+ _cleanup_free_ char *n1 = NULL, *n2 = NULL, *user_a = NULL, *user_b = NULL;
+ struct stat st;
if (!FLAGS_SET(flags, CHASE_WARN))
return -ENOLINK;
@@ -753,9 +751,14 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags)
(void) fd_get_path(a, &n1);
(void) fd_get_path(b, &n2);
+ if (fstat(a, &st) == 0)
+ user_a = uid_to_name(st.st_uid);
+ if (fstat(b, &st) == 0)
+ user_b = uid_to_name(st.st_uid);
+
return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
- "Detected unsafe path transition %s %s %s during canonicalization of %s.",
- strna(n1), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), path);
+ "Detected unsafe path transition %s (owned by %s) %s %s (owned by %s) during canonicalization of %s.",
+ strna(n1), strna(user_a), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), strna(user_b), path);
}
static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
@@ -1375,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) {
@@ -1409,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;
@@ -1466,12 +1484,56 @@ int fsync_path_at(int at_fd, const char *path) {
return 0;
}
+int fsync_parent_at(int at_fd, const char *path) {
+ _cleanup_close_ int opened_fd = -1;
+
+ if (isempty(path)) {
+ if (at_fd != AT_FDCWD)
+ return fsync_directory_of_file(at_fd);
+
+ opened_fd = open("..", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ if (opened_fd < 0)
+ return -errno;
+
+ if (fsync(opened_fd) < 0)
+ return -errno;
+
+ return 0;
+ }
+
+ opened_fd = openat(at_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+ if (opened_fd < 0)
+ return -errno;
+
+ return fsync_directory_of_file(opened_fd);
+}
+
+int fsync_path_and_parent_at(int at_fd, const char *path) {
+ _cleanup_close_ int opened_fd = -1;
+
+ if (isempty(path)) {
+ if (at_fd != AT_FDCWD)
+ return fsync_full(at_fd);
+
+ opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ } else
+ opened_fd = openat(at_fd, path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC);
+ if (opened_fd < 0)
+ return -errno;
+
+ return fsync_full(opened_fd);
+}
+
int syncfs_path(int atfd, const char *path) {
_cleanup_close_ int fd = -1;
- assert(path);
+ if (isempty(path)) {
+ if (atfd != AT_FDCWD)
+ return syncfs(atfd) < 0 ? -errno : 0;
- fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
+ fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ } else
+ fd = openat(atfd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0)
return -errno;
@@ -1504,91 +1566,6 @@ int open_parent(const char *path, int flags, mode_t mode) {
return fd;
}
-static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
- _cleanup_free_ char *p = NULL, *uuids = NULL;
- _cleanup_closedir_ DIR *d = NULL;
- int r, found_encrypted = false;
-
- assert(sysfs_path);
-
- if (depth_left == 0)
- return -EINVAL;
-
- p = path_join(sysfs_path, "dm/uuid");
- if (!p)
- return -ENOMEM;
-
- r = read_one_line_file(p, &uuids);
- if (r != -ENOENT) {
- if (r < 0)
- return r;
-
- /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
- if (startswith(uuids, "CRYPT-"))
- return true;
- }
-
- /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
- * subdir. */
-
- p = mfree(p);
- p = path_join(sysfs_path, "slaves");
- if (!p)
- return -ENOMEM;
-
- d = opendir(p);
- if (!d) {
- if (errno == ENOENT) /* Doesn't have underlying devices */
- return false;
-
- return -errno;
- }
-
- for (;;) {
- _cleanup_free_ char *q = NULL;
- struct dirent *de;
-
- errno = 0;
- de = readdir_no_dot(d);
- if (!de) {
- if (errno != 0)
- return -errno;
-
- break; /* No more underlying devices */
- }
-
- q = path_join(p, de->d_name);
- if (!q)
- return -ENOMEM;
-
- r = blockdev_is_encrypted(q, depth_left - 1);
- if (r < 0)
- return r;
- if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
- return false;
-
- found_encrypted = true;
- }
-
- return found_encrypted;
-}
-
-int path_is_encrypted(const char *path) {
- char p[SYS_BLOCK_PATH_MAX(NULL)];
- dev_t devt;
- int r;
-
- r = get_block_device(path, &devt);
- if (r < 0)
- return r;
- if (r == 0) /* doesn't have a block device */
- return false;
-
- xsprintf_sys_block_path(p, NULL, devt);
-
- return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
-}
-
int conservative_renameat(
int olddirfd, const char *oldpath,
int newdirfd, const char *newpath) {