From addc3e302dad239fb11cf280b0ce4761fe07e015 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Tue, 20 Mar 2018 08:58:48 +0100 Subject: [PATCH] tmpfiles: don't follow unsafe transitions in path_set_*() Since all path_set_*() helpers don't follow symlinks, it's possible to use chase_symlinks(CHASE_NOFOLLOW) flag to both open the files specified by the passed paths and check their validity (unlike their counterpart fd_set_*() helpers). --- src/tmpfiles/tmpfiles.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 71f8dec49b..cfd9044c5b 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -864,15 +864,38 @@ static int path_open_parent_safe(const char *path) { return fd; } +static int path_open_safe(const char *path) { + int fd; + + /* path_open_safe() returns a file descriptor opened with O_PATH after + * verifying that the path doesn't contain unsafe transitions, except + * for its final component as the function does not follow symlink. */ + + assert(path); + + if (!path_is_normalized(path)) { + log_error("Failed to open invalid path '%s'.", path); + return -EINVAL; + } + + fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_NOFOLLOW, NULL); + if (fd == -EPERM) + return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path); + if (fd < 0) + return log_error_errno(fd, "Failed to validate path %s: %m", path); + + return fd; +} + static int path_set_perms(Item *i, const char *path) { _cleanup_close_ int fd = -1; assert(i); assert(path); - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + fd = path_open_safe(path); if (fd < 0) - return log_error_errno(errno, "Failed to open \"%s\" to adjust permissions: %m", path); + return fd; return fd_set_perms(i, fd, NULL); } @@ -945,9 +968,9 @@ static int path_set_xattrs(Item *i, const char *path) { assert(i); assert(path); - fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH); + fd = path_open_safe(path); if (fd < 0) - return log_error_errno(errno, "Cannot open '%s': %m", path); + return fd; return fd_set_xattrs(i, fd, NULL); } @@ -1076,9 +1099,9 @@ static int path_set_acls(Item *item, const char *path) { assert(item); assert(path); - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + fd = path_open_safe(path); if (fd < 0) - return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); + return fd; r = fd_set_acls(item, fd, NULL); #endif @@ -1238,9 +1261,9 @@ static int path_set_attribute(Item *item, const char *path) { if (!item->attribute_set || item->attribute_mask == 0) return 0; - fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH); + fd = path_open_safe(path); if (fd < 0) - return log_error_errno(errno, "Cannot open '%s': %m", path); + return fd; return fd_set_attribute(item, fd, NULL); }