port write_env_file() to label_os_pre() + teach firstboot a bit of relabelling (#37869)

This is a clean-up, and also addresses some of the points of #37857.
This commit is contained in:
Yu Watanabe
2025-06-19 18:03:12 +09:00
committed by GitHub
20 changed files with 87 additions and 105 deletions
+4
View File
@@ -120,6 +120,10 @@ Deprecations and removals:
Features:
* replace symlink_label(), mknodat_label(), btrfs_subvol_make_label(),
mkdir_label() and related calls by flags-based calls that use
label_ops_pre()/label_ops_post().
* maybe reconsider whether virtualization consoles (hvc1) are considered local
or remote. i.e. are they more like an ssh login, or more like a /dev/tty1
login? Lennart used to believe the former, but maybe the latter is more
+15 -2
View File
@@ -5,10 +5,12 @@
#include "alloc-util.h"
#include "env-file.h"
#include "env-util.h"
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "label.h"
#include "log.h"
#include "string-util.h"
#include "strv.h"
@@ -629,7 +631,7 @@ static void write_env_var(FILE *f, const char *v) {
fputc_unlocked('\n', f);
}
int write_env_file(int dir_fd, const char *fname, char **headers, char **l) {
int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
@@ -637,7 +639,18 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(fname);
bool call_label_ops_post = false;
if (FLAGS_SET(flags, WRITE_ENV_FILE_LABEL)) {
r = label_ops_pre(dir_fd, fname, S_IFREG);
if (r < 0)
return r;
call_label_ops_post = true;
}
r = fopen_tmpfile_linkable_at(dir_fd, fname, O_WRONLY|O_CLOEXEC, &p, &f);
if (call_label_ops_post)
RET_GATHER(r, label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f));
if (r < 0)
return r;
@@ -672,5 +685,5 @@ int write_vconsole_conf(int dir_fd, const char *fname, char **l) {
"# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed",
"# and systemd-vconsole-setup(8). Use localectl(1) to update this file.");
return write_env_file(dir_fd, fname, headers, l);
return write_env_file(dir_fd, fname, headers, l, WRITE_ENV_FILE_LABEL);
}
+5 -1
View File
@@ -15,7 +15,11 @@ int load_env_file_pairs_fd(int fd, const char *fname, char ***ret);
int merge_env_file(char ***env, FILE *f, const char *fname);
int write_env_file(int dir_fd, const char *fname, char **headers, char **l);
typedef enum WriteEnvFileFlags {
WRITE_ENV_FILE_LABEL = 1 << 0,
} WriteEnvFileFlags;
int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags);
int write_vconsole_conf(int dir_fd, const char *fname, char **l);
+18 -5
View File
@@ -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) {
+7 -2
View File
@@ -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);
+1 -1
View File
@@ -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);
+17 -6
View File
@@ -28,6 +28,8 @@
#include "hostname-util.h"
#include "image-policy.h"
#include "kbd-util.h"
#include "label.h"
#include "label-util.h"
#include "libcrypt-util.h"
#include "locale-util.h"
#include "lock-util.h"
@@ -447,7 +449,12 @@ static int process_locale(int rfd) {
locales[i] = NULL;
r = write_env_file(pfd, f, NULL, locales);
r = write_env_file(
pfd,
f,
/* headers= */ NULL,
locales,
WRITE_ENV_FILE_LABEL);
if (r < 0)
return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
@@ -640,7 +647,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 +665,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");
@@ -725,7 +732,7 @@ static int process_hostname(int rfd) {
return 0;
r = write_string_file_at(pfd, f, arg_hostname,
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
if (r < 0)
return log_error_errno(r, "Failed to write /etc/hostname: %m");
@@ -758,7 +765,7 @@ static int process_machine_id(int rfd) {
}
r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
if (r < 0)
return log_error_errno(r, "Failed to write /etc/machine-id: %m");
@@ -1184,7 +1191,7 @@ static int process_kernel_cmdline(int rfd) {
}
r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC);
WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
if (r < 0)
return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
@@ -1679,6 +1686,10 @@ static int run(int argc, char *argv[]) {
}
}
r = mac_init();
if (r < 0)
return r;
if (arg_image) {
assert(!arg_root);
+6 -2
View File
@@ -21,7 +21,6 @@
#include "daemon-util.h"
#include "device-private.h"
#include "env-file.h"
#include "env-file-label.h"
#include "env-util.h"
#include "extract-word.h"
#include "fileio.h"
@@ -860,7 +859,12 @@ static int context_write_data_machine_info(Context *c) {
return 0;
}
r = write_env_file_label(AT_FDCWD, "/etc/machine-info", NULL, l);
r = write_env_file(
AT_FDCWD,
"/etc/machine-info",
/* headers= */ NULL,
l,
WRITE_ENV_FILE_LABEL);
if (r < 0)
return r;
+1 -2
View File
@@ -8,7 +8,6 @@
#include "alloc-util.h"
#include "copy.h"
#include "env-file.h"
#include "env-file-label.h"
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
@@ -315,7 +314,7 @@ int vconsole_write_data(Context *c) {
return 0;
}
r = write_vconsole_conf_label(l);
r = write_vconsole_conf(AT_FDCWD, "/etc/vconsole.conf", l);
if (r < 0)
return r;
+1 -1
View File
@@ -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);
}
-35
View File
@@ -1,35 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/stat.h>
#include "env-file.h"
#include "env-file-label.h"
#include "selinux-util.h"
int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l) {
int r;
r = mac_selinux_create_file_prepare(fname, S_IFREG);
if (r < 0)
return r;
r = write_env_file(dir_fd, fname, headers, l);
mac_selinux_create_file_clear();
return r;
}
int write_vconsole_conf_label(char **l) {
int r;
r = mac_selinux_create_file_prepare("/etc/vconsole.conf", S_IFREG);
if (r < 0)
return r;
r = write_vconsole_conf(AT_FDCWD, "/etc/vconsole.conf", l);
mac_selinux_create_file_clear();
return r;
}
-12
View File
@@ -1,12 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "forward.h"
/* These functions are split out of fileio.h (and not for example just flags to the functions they wrap) in order to
* optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux, but not
* for all */
int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l);
int write_vconsole_conf_label(char **l);
-19
View File
@@ -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;
-4
View File
@@ -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) {
+6 -2
View File
@@ -6,7 +6,6 @@
#include "alloc-util.h"
#include "env-file.h"
#include "env-file-label.h"
#include "env-util.h"
#include "errno-util.h"
#include "fd-util.h"
@@ -212,7 +211,12 @@ int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) {
return 0;
}
r = write_env_file_label(AT_FDCWD, "/etc/locale.conf", NULL, set);
r = write_env_file(
AT_FDCWD,
"/etc/locale.conf",
/* headers= */ NULL,
set,
WRITE_ENV_FILE_LABEL);
if (r < 0)
return r;
-1
View File
@@ -68,7 +68,6 @@ shared_sources = files(
'efi-loader.c',
'elf-util.c',
'enable-mempool.c',
'env-file-label.c',
'ethtool-util.c',
'exec-util.c',
'exit-status.c',
+1 -1
View File
@@ -171,7 +171,7 @@ TEST(write_and_load_env_file) {
assert_se(tempfn_random_child(NULL, NULL, &p) >= 0);
assert_se(j = strjoin("TEST=", v));
assert_se(write_env_file(AT_FDCWD, p, STRV_MAKE("# header 1", "", "# header 2"), STRV_MAKE(j)) >= 0);
assert_se(write_env_file(AT_FDCWD, p, STRV_MAKE("# header 1", "", "# header 2"), STRV_MAKE(j), /* flags= */ 0) >= 0);
assert_se(cmd = strjoin(". ", p, " && /bin/echo -n \"$TEST\""));
assert_se(f = popen(cmd, "re"));
+2 -2
View File
@@ -143,7 +143,7 @@ TEST(parse_env_file) {
assert_se(fd >= 0);
}
r = write_env_file(AT_FDCWD, p, NULL, a);
r = write_env_file(AT_FDCWD, p, /* headers= */ NULL, a, /* flags= */ 0);
assert_se(r >= 0);
r = load_env_file(NULL, p, &b);
@@ -206,7 +206,7 @@ TEST(parse_multiline_env_file) {
assert_se(fd >= 0);
}
r = write_env_file(AT_FDCWD, p, NULL, a);
r = write_env_file(AT_FDCWD, p, /* headers= */ NULL, a, /* flags= */ 0);
assert_se(r >= 0);
r = load_env_file(NULL, p, &b);
+2 -6
View File
@@ -2471,17 +2471,13 @@ 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)
return log_error_errno(r, "rm -rf %s failed: %m", i->path);
mac_selinux_create_file_prepare(i->path, S_IFLNK);
r = RET_NERRNO(symlinkat(i->argument, pfd, i->path));
mac_selinux_create_file_clear();
r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL);
}
if (r < 0)
return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
+1 -1
View File
@@ -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);