summaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-10-21 22:58:25 +0200
committerLennart Poettering <lennart@poettering.net>2024-10-22 17:51:26 +0200
commit4946dd4197efee693432b3ddff56f30205d3bdfd (patch)
treea9ef5d79b2a092cac29246487ed81c9ccb272ec2 /src/test
parentfs-util: always call label post ops in xopenat_full(), in both success and er... (diff)
downloadsystemd-4946dd4197efee693432b3ddff56f30205d3bdfd.tar.xz
systemd-4946dd4197efee693432b3ddff56f30205d3bdfd.zip
fs-util: tweak how openat_report_new() operates when O_CREAT is used on a dangling symlink
One of the big mistakes of Linux is that when you create a file with open() and O_CREAT and the file already exists as dangling symlink that the symlink will be followed and the file created that it points to. This has resulted in many vulnerabilities, and triggered the creation of the O_MOFOLLOW flag, addressing the problem. O_NOFOLLOW is less than ideal in many ways, but in particular one: when actually creating a file it makes sense to set, because it is a problem to follow final symlinks in that case. But if the file is already existing, it actually does make sense to follow the symlinks. With openat_report_new() we distinguish these two cases anyway (the whole function exists only to distinguish the create and the exists-already case after all), hence let's do something about this: let's simply never create files "through symlinks". This can be implemented very easily: just pass O_NOFOLLOW to the 2nd openat() call, where we actually create files. And then basically remove 0dd82dab91eaac5e7b17bd5e9a1e07c6d2b78dca again, because we don't need to care anymore, we already will see ELOOP when we touch a symlink. Note that this change means that openat_report_new() will thus start to deviate from plain openat() behaviour in this one small detail: when actually creating files we will *never* follow the symlink. That should be a systematic improvement of security. Fixes: #34088
Diffstat (limited to 'src/test')
-rw-r--r--src/test/test-fs-util.c3
-rw-r--r--src/test/test-id128.c5
2 files changed, 5 insertions, 3 deletions
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 3da3caf4ab..55202240d3 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -670,6 +670,9 @@ TEST(openat_report_new) {
ASSERT_OK_ERRNO(symlinkat("target", tfd, "link"));
fd = openat_report_new(tfd, "link", O_RDWR|O_CREAT, 0666, &b);
+ ASSERT_ERROR(fd, EEXIST);
+
+ fd = openat_report_new(tfd, "target", O_RDWR|O_CREAT, 0666, &b);
ASSERT_OK(fd);
fd = safe_close(fd);
ASSERT_TRUE(b);
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index a6ed640bd6..eb3bfec2bb 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -286,9 +286,8 @@ TEST(id128_at) {
ASSERT_OK_ERRNO(unlinkat(tfd, "etc/machine-id", 0));
ASSERT_OK(id128_write_at(tfd, "etc2/machine-id", ID128_FORMAT_PLAIN, id));
ASSERT_OK_ERRNO(unlinkat(tfd, "etc/machine-id", 0));
- ASSERT_OK(id128_write_at(tfd, "etc/hoge-id", ID128_FORMAT_PLAIN, id));
- ASSERT_OK_ERRNO(unlinkat(tfd, "etc/machine-id", 0));
- ASSERT_OK(id128_write_at(tfd, "etc2/hoge-id", ID128_FORMAT_PLAIN, id));
+ ASSERT_ERROR(id128_write_at(tfd, "etc/hoge-id", ID128_FORMAT_PLAIN, id), EEXIST);
+ ASSERT_OK(id128_write_at(tfd, "etc2/machine-id", ID128_FORMAT_PLAIN, id));
/* id128_read_at() */
i = SD_ID128_NULL; /* Not necessary in real code, but for testing that the id is really assigned. */