mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
tmpfile-util: add new LINK_TMPFILE_SYNC flag for syncing properly before/after linking in the file
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.
This commit is contained in:
@@ -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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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 = 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. */
|
||||
|
||||
r = tempfn_random(target, NULL, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user