From: Franck Bui Date: Fri, 13 Apr 2018 15:50:49 +0000 (+0200) Subject: tmpfiles: make truncate_file() safe X-Git-Tag: v240~864^2~21 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=14ab804e14edfa224430ed2c8182864034c9075d;p=thirdparty%2Fsystemd.git tmpfiles: make truncate_file() safe --- diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index dd19cde13a5..28e65502436 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1367,10 +1367,11 @@ static int create_file(Item *i, const char *path) { } static int truncate_file(Item *i, const char *path) { - _cleanup_close_ int fd = -1; + _cleanup_close_ int fd = -1, dir_fd = -1; struct stat stbuf, *st = NULL; bool erofs = false; int r = 0; + char *bn; assert(i); assert(path); @@ -1381,9 +1382,17 @@ static int truncate_file(Item *i, const char *path) { * fifo nor a terminal device. Therefore we first open the file and make * sure it's a regular one before truncating it. */ + /* Validate the path and keep the fd on the directory for opening the + * file so we're sure that it can't be changed behind our back. */ + dir_fd = path_open_parent_safe(path); + if (dir_fd < 0) + return dir_fd; + + bn = basename(path); + RUN_WITH_UMASK(0000) { mac_selinux_create_file_prepare(path, S_IFREG); - fd = open(path, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode); + fd = openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode); mac_selinux_create_file_clear(); } @@ -1397,7 +1406,7 @@ static int truncate_file(Item *i, const char *path) { * operations fail with EROFS if they try to modify the target * file. */ - fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode); + fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode); if (fd < 0) { if (errno == ENOENT) { log_error("Cannot create file %s on a read-only file system.", path);