]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fs-util: add new CHASE_WARN flag to chase_symlinks()
authorFranck Bui <fbui@suse.com>
Thu, 29 Nov 2018 10:08:52 +0000 (11:08 +0100)
committerFranck Bui <fbui@suse.com>
Fri, 30 Nov 2018 12:30:26 +0000 (13:30 +0100)
This flag can be used to make chase_symlinks() emit a warning when it
encounters an error.

Such flag can be useful for generating a comprehensive and detailed warning
since chase_symlinks() can generate a warning with a full context.

For now only warnings for unsafe transitions are produced.

src/basic/fs-util.c
src/basic/fs-util.h

index 55651baa80c2283c01173c9c39286ff88e1ec5bf..e45ad06491aaf375890f41ddc1c9a2bd9f39cf9a 100644 (file)
@@ -15,6 +15,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "locale-util.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
@@ -644,6 +645,20 @@ static bool safe_transition(const struct stat *a, const struct stat *b) {
         return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */
 }
 
+static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
+        _cleanup_free_ char *n1 = NULL, *n2 = NULL;
+
+        if (!FLAGS_SET(flags, CHASE_WARN))
+                return -EPERM;
+
+        (void) fd_get_path(a, &n1);
+        (void) fd_get_path(b, &n2);
+
+        return log_warning_errno(SYNTHETIC_ERRNO(EPERM),
+                                 "Detected unsafe path transition %s %s %s during canonicalization of %s.",
+                                 n1, special_glyph(ARROW), n2, path);
+}
+
 int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
         _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
         _cleanup_close_ int fd = -1;
@@ -819,7 +834,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                         return -errno;
 
                                 if (!safe_transition(&previous_stat, &st))
-                                        return -EPERM;
+                                        return log_unsafe_transition(fd, fd_parent, path, flags);
 
                                 previous_stat = st;
                         }
@@ -860,7 +875,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         return -errno;
                 if ((flags & CHASE_SAFE) &&
                     !safe_transition(&previous_stat, &st))
-                        return -EPERM;
+                        return log_unsafe_transition(fd, child, path, flags);
 
                 previous_stat = st;
 
@@ -899,7 +914,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                                 return -errno;
 
                                         if (!safe_transition(&previous_stat, &st))
-                                                return -EPERM;
+                                                return log_unsafe_transition(child, fd, path, flags);
 
                                         previous_stat = st;
                                 }
index 955b146a6a4c62fd67c8312763b656fa2b1e3a36..7ad030be5d0e4a7c71a136e371f953892b4b81dd 100644 (file)
@@ -74,6 +74,7 @@ enum {
         CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */
         CHASE_STEP        = 1 << 6, /* If set, just execute a single step of the normalization */
         CHASE_NOFOLLOW    = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
+        CHASE_WARN        = 1 << 8, /* Emit an appropriate warning when an error is encountered */
 };
 
 /* How many iterations to execute before returning -ELOOP */