]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfile-util: add new LINK_TMPFILE_SYNC flag for syncing properly before/after linkin...
authorLennart Poettering <lennart@poettering.net>
Tue, 13 Jun 2023 07:45:39 +0000 (09:45 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 13 Jun 2023 07:45:39 +0000 (09:45 +0200)
This syncs the data before linking it in, and both data + dir once done.
This should give us proper semantics for installing files safely into
the fs.

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

index fdc66c5b5e2468c2adf8365f97455b24555585a2..e77ca9424892d7a113b258c388a04edabfa9282e 100644 (file)
@@ -17,6 +17,7 @@
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "sync-util.h"
 #include "tmpfile-util.h"
 #include "umask-util.h"
 
@@ -361,34 +362,46 @@ int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, Li
          * an fd created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE
          * is not supported on the directory, and renameat2() is used instead. */
 
+        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC) && fsync(fd) < 0)
+                return -errno;
+
         if (path) {
                 if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
-                        return RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+                        r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+                else
+                        r = rename_noreplace(dir_fd, path, dir_fd, target);
+                if (r < 0)
+                        return r;
+        } else {
 
-                return rename_noreplace(dir_fd, path, dir_fd, target);
-        }
+                r = link_fd(fd, dir_fd, target);
+                if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+                        return r;
 
-        r = link_fd(fd, dir_fd, target);
-        if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
-                return r;
+                /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
+                 * linkat() logic does not allow that. We work-around this by linking the file to a random name
+                 * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
+                 * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
+                 * system under a temporary name) is very short. */
 
-        /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
-         * linkat() logic does not allow that. We work-around this by linking the file to a random name
-         * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
-         * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
-         * system under a temporary name) is very short. */
+                r = tempfn_random(target, NULL, &tmp);
+                if (r < 0)
+                        return r;
 
-        r = tempfn_random(target, NULL, &tmp);
-        if (r < 0)
-                return r;
+                if (link_fd(fd, dir_fd, tmp) < 0)
+                        return -EEXIST; /* propagate original error */
 
-        if (link_fd(fd, dir_fd, tmp) < 0)
-                return -EEXIST; /* propagate original error */
+                r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
+                if (r < 0) {
+                        (void) unlinkat(dir_fd, tmp, 0);
+                        return r;
+                }
+        }
 
-        r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
-        if (r < 0) {
-                (void) unlinkat(dir_fd, tmp, 0);
-                return r;
+        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
+                r = fsync_full(fd);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -404,7 +417,7 @@ int flink_tmpfile(FILE *f, const char *path, const char *target, LinkTmpfileFlag
         if (fd < 0) /* Not all FILE* objects encapsulate fds */
                 return -EBADF;
 
-        r = fflush_sync_and_check(f);
+        r = fflush_and_check(f);
         if (r < 0)
                 return r;
 
index 44e9b75f22119c9d4015f919463e2c89f9a0473f..50904ecac104c94a400a10cc39ebe1b1f9208963 100644 (file)
@@ -32,6 +32,7 @@ int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE
 
 typedef enum LinkTmpfileFlags {
         LINK_TMPFILE_REPLACE = 1 << 0,
+        LINK_TMPFILE_SYNC    = 1 << 1,
 } LinkTmpfileFlags;
 
 int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags);