diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 55651baa80..e45ad06491 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -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; } diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 955b146a6a..7ad030be5d 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -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 */