From 9ea5a6e7d6b93dda35f7c9147bcbd44105032d6d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 18 Jun 2025 10:14:09 +0200 Subject: [PATCH] fs-util: replace symlink_atomic_full_label() by a flag to symlinkat_atomic_full() More porting work to label_ops_pre()/label_ops_post() This also enables labelling of the /etc/localtime symlink in systemd-firstboot, which should address one small facet of #37857 --- src/basic/fs-util.c | 23 ++++++++++++++++++----- src/basic/fs-util.h | 9 +++++++-- src/core/unit.c | 2 +- src/firstboot/firstboot.c | 5 +++-- src/resolve/resolved-resolv-conf.c | 2 +- src/shared/label-util.c | 19 ------------------- src/shared/label-util.h | 4 ---- src/tmpfiles/tmpfiles.c | 4 +--- src/udev/udev-node.c | 2 +- 9 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 04f7290cc2c..3dd32ccac67 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -459,14 +459,14 @@ int symlinkat_idempotent(const char *from, int atfd, const char *to, bool make_r return 0; } -int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative) { - _cleanup_free_ char *relpath = NULL, *t = NULL; +int symlinkat_atomic_full(const char *from, int atfd, const char *to, SymlinkFlags flags) { int r; assert(from); assert(to); - if (make_relative) { + _cleanup_free_ char *relpath = NULL; + if (FLAGS_SET(flags, SYMLINK_MAKE_RELATIVE)) { r = path_make_relative_parent(to, from, &relpath); if (r < 0) return r; @@ -474,12 +474,25 @@ int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_ from = relpath; } + _cleanup_free_ char *t = NULL; r = tempfn_random(to, NULL, &t); if (r < 0) return r; - if (symlinkat(from, atfd, t) < 0) - return -errno; + bool call_label_ops_post = false; + if (FLAGS_SET(flags, SYMLINK_LABEL)) { + r = label_ops_pre(atfd, to, S_IFLNK); + if (r < 0) + return r; + + call_label_ops_post = true; + } + + r = RET_NERRNO(symlinkat(from, atfd, t)); + if (call_label_ops_post) + RET_GATHER(r, label_ops_post(atfd, t, /* created= */ r >= 0)); + if (r < 0) + return r; r = RET_NERRNO(renameat(atfd, t, atfd, to)); if (r < 0) { diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 59dbb1ce0ee..1150f914be3 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -48,9 +48,14 @@ static inline int symlink_idempotent(const char *from, const char *to, bool make return symlinkat_idempotent(from, AT_FDCWD, to, make_relative); } -int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative); +typedef enum SymlinkFlags { + SYMLINK_MAKE_RELATIVE = 1 << 0, + SYMLINK_LABEL = 1 << 1, +} SymlinkFlags; + +int symlinkat_atomic_full(const char *from, int atfd, const char *to, SymlinkFlags flags); static inline int symlink_atomic(const char *from, const char *to) { - return symlinkat_atomic_full(from, AT_FDCWD, to, false); + return symlinkat_atomic_full(from, AT_FDCWD, to, 0); } int mknodat_atomic(int atfd, const char *path, mode_t mode, dev_t dev); diff --git a/src/core/unit.c b/src/core/unit.c index 19d0898f9bb..1f46b96ad95 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -5677,7 +5677,7 @@ static int unit_export_invocation_id(Unit *u) { if (r < 0) return log_unit_debug_errno(u, r, "Failed to get invocation path: %m"); - r = symlink_atomic_label(u->invocation_id_string, p); + r = symlinkat_atomic_full(u->invocation_id_string, AT_FDCWD, p, SYMLINK_LABEL); if (r < 0) return log_unit_debug_errno(u, r, "Failed to create invocation ID symlink %s: %m", p); diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 6ba7d4ba921..2f0fd9efeda 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -28,6 +28,7 @@ #include "hostname-util.h" #include "image-policy.h" #include "kbd-util.h" +#include "label.h" #include "libcrypt-util.h" #include "locale-util.h" #include "lock-util.h" @@ -640,7 +641,7 @@ static int process_timezone(int rfd) { if (r < 0) return log_error_errno(r, "Failed to read host's /etc/localtime: %m"); - r = symlinkat_atomic_full(s, pfd, f, /* make_relative= */ false); + r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL); if (r < 0) return log_error_errno(r, "Failed to create /etc/localtime symlink: %m"); @@ -658,7 +659,7 @@ static int process_timezone(int rfd) { e = strjoina("../usr/share/zoneinfo/", arg_timezone); - r = symlinkat_atomic_full(e, pfd, f, /* make_relative= */ false); + r = symlinkat_atomic_full(e, pfd, f, SYMLINK_LABEL); if (r < 0) return log_error_errno(r, "Failed to create /etc/localtime symlink: %m"); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 0064adb948e..d0b5d7340d6 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -377,7 +377,7 @@ int manager_write_resolv_conf(Manager *m) { if (r < 0) return log_warning_errno(r, "Failed to extract filename from path '" PRIVATE_UPLINK_RESOLV_CONF "', ignoring: %m"); - r = symlink_atomic_label(fname, PRIVATE_STUB_RESOLV_CONF); + r = symlinkat_atomic_full(fname, AT_FDCWD, PRIVATE_STUB_RESOLV_CONF, SYMLINK_LABEL); if (r < 0) log_warning_errno(r, "Failed to symlink %s, ignoring: %m", PRIVATE_STUB_RESOLV_CONF); } diff --git a/src/shared/label-util.c b/src/shared/label-util.c index b4d5d4505a8..78d5501c9fc 100644 --- a/src/shared/label-util.c +++ b/src/shared/label-util.c @@ -60,25 +60,6 @@ int symlink_label(const char *old_path, const char *new_path) { return mac_smack_fix(new_path, 0); } -int symlink_atomic_full_label(const char *from, const char *to, bool make_relative) { - int r; - - assert(from); - assert(to); - - r = mac_selinux_create_file_prepare(to, S_IFLNK); - if (r < 0) - return r; - - r = symlinkat_atomic_full(from, AT_FDCWD, to, make_relative); - mac_selinux_create_file_clear(); - - if (r < 0) - return r; - - return mac_smack_fix(to, 0); -} - int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev) { int r; diff --git a/src/shared/label-util.h b/src/shared/label-util.h index b135c0f1ab7..b1586dd81ed 100644 --- a/src/shared/label-util.h +++ b/src/shared/label-util.h @@ -16,10 +16,6 @@ static inline int label_fix(const char *path, LabelFixFlags flags) { } int symlink_label(const char *old_path, const char *new_path); -int symlink_atomic_full_label(const char *from, const char *to, bool make_relative); -static inline int symlink_atomic_label(const char *from, const char *to) { - return symlink_atomic_full_label(from, to, false); -} int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev); static inline int mknod_label(const char *pathname, mode_t mode, dev_t dev) { diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index a11a90b93bc..5a4fcc61173 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2471,9 +2471,7 @@ static int create_symlink(Context *c, Item *i) { fd = safe_close(fd); - mac_selinux_create_file_prepare(i->path, S_IFLNK); - r = symlinkat_atomic_full(i->argument, pfd, bn, /* make_relative= */ false); - mac_selinux_create_file_clear(); + r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL); if (IN_SET(r, -EISDIR, -EEXIST, -ENOTEMPTY)) { r = rm_rf_child(pfd, bn, REMOVE_PHYSICAL); if (r < 0) diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 5f165b5107a..a48061a1ea7 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -70,7 +70,7 @@ static int node_create_symlink(sd_device *dev, const char *devnode, const char * return log_device_debug_errno(dev, r, "Failed to create parent directory of '%s': %m", slink); /* use relative link */ - r = symlink_atomic_full_label(devnode, slink, /* make_relative = */ true); + r = symlinkat_atomic_full(devnode, AT_FDCWD, slink, SYMLINK_MAKE_RELATIVE|SYMLINK_LABEL); if (r < 0) return log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink, devnode); -- 2.47.3