]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
selinux: wire up LabelContext in tmpfiles, firstboot, sysusers 42768/head
authorSimon de Vlieger <cmdr@supakeen.com>
Sat, 4 Jul 2026 11:10:21 +0000 (13:10 +0200)
committerSimon de Vlieger <cmdr@supakeen.com>
Fri, 31 Jul 2026 08:06:14 +0000 (10:06 +0200)
These three one-shot tools operate on alternate roots via --root/--image
but until now created files with host SELinux labels, producing images
that fail to boot or run with enforcing mode because every file carries
the wrong security context.

Create a LabelContext from arg_root at startup and thread it through all
labeling call sites so the target image gets labeled according to its own
policy.

Signed-off-by: Simon de Vlieger <cmdr@supakeen.com>
src/firstboot/firstboot.c
src/sysusers/sysusers.c
src/tmpfiles/tmpfiles.c

index ed6817a186e0a6cfbc30d96babccea595e152a5e..a76b4c755e4b693aa897a83d7e270ec63208ea93 100644 (file)
@@ -94,6 +94,7 @@ static bool arg_reset = false;
 static ImagePolicy *arg_image_policy = NULL;
 static bool arg_chrome = true;
 static bool arg_mute_console = false;
+static LabelContext *arg_label_context = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -107,6 +108,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_label_context, mac_label_context_freep);
 
 static bool welcome_done = false;
 
@@ -408,12 +410,13 @@ static int process_locale(int rfd, sd_varlink **mute_console_link) {
 
         locales[i] = NULL;
 
-        r = write_env_file(
+        r = write_env_file_label(
                         pfd,
                         f,
                         /* headers= */ NULL,
                         locales,
-                        WRITE_ENV_FILE_LABEL);
+                        WRITE_ENV_FILE_LABEL,
+                        arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
 
@@ -653,7 +656,7 @@ static int process_timezone(int rfd, sd_varlink **mute_console_link) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
 
-                        r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL);
+                        r = symlinkat_atomic_full_label(s, pfd, f, SYMLINK_LABEL, arg_label_context);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
 
@@ -674,7 +677,7 @@ static int process_timezone(int rfd, sd_varlink **mute_console_link) {
         if (r < 0)
                 return r;
 
-        r = symlinkat_atomic_full(relpath, pfd, f, SYMLINK_LABEL);
+        r = symlinkat_atomic_full_label(relpath, pfd, f, SYMLINK_LABEL, arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
 
@@ -779,8 +782,9 @@ static int process_hostname(int rfd, sd_varlink **mute_console_link) {
                         hostname = resolved;
         }
 
-        r = write_string_file_at(pfd, f, hostname,
-                                 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
+        r = write_string_file_full_label(pfd, f, hostname,
+                                   WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
+                                   /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to write /etc/hostname: %m");
 
@@ -812,8 +816,9 @@ static int process_machine_id(int rfd) {
                 return 0;
         }
 
-        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_LABEL);
+        r = write_string_file_full_label(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_LABEL,
+                                   /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to write /etc/machine-id: %m");
 
@@ -874,11 +879,12 @@ static int process_machine_tags(int rfd) {
         if (!c)
                 return log_oom();
 
-        r = write_string_file_at(
+        r = write_string_file_full_label(
                         pfd,
                         "machine-info",
                         c,
-                        WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
+                        WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
+                        /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to write /etc/machine-info: %m");
 
@@ -1038,7 +1044,7 @@ static int write_root_passwd(int rfd, int etc_fd, const char *password, const ch
         int r;
         bool found = false;
 
-        r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp, /* label_context= */ NULL);
+        r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp, arg_label_context);
         if (r < 0)
                 return r;
 
@@ -1109,7 +1115,7 @@ static int write_root_shadow(int etc_fd, const char *hashed_password) {
         int r;
         bool found = false;
 
-        r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp, /* label_context= */ NULL);
+        r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp, arg_label_context);
         if (r < 0)
                 return r;
 
@@ -1319,8 +1325,9 @@ static int process_kernel_cmdline(int rfd) {
                 return 0;
         }
 
-        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_LABEL);
+        r = write_string_file_full_label(pfd, "cmdline", arg_kernel_cmdline,
+                                   WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
+                                   /* ts= */ NULL, /* label_fn= */ NULL, arg_label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
 
@@ -1777,6 +1784,10 @@ static int run(int argc, char *argv[]) {
                         return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
         }
 
+        r = mac_label_context_new(arg_root, &arg_label_context);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
+
         LOG_SET_PREFIX(arg_image ?: arg_root);
         DEFER_VOID_CALL(end_marker);
         DEFER_VOID_CALL(chrome_hide);
index 9c52bce66bd7821556b7256ab71de608061a226f..56f3dc3953a2db91aa4d6e29846a537ae4d4c402 100644 (file)
@@ -132,6 +132,8 @@ typedef struct Context {
 
         UGIDAllocationRange login_defs;
         bool login_defs_need_warning;
+
+        LabelContext *label_context;
 } Context;
 
 static void context_done(Context *c) {
@@ -152,6 +154,7 @@ static void context_done(Context *c) {
 
         set_free(c->names);
         uid_range_free(c->uid_range);
+        mac_label_context_free(c->label_context);
 }
 
 static void maybe_emit_login_defs_warning(Context *c) {
@@ -303,7 +306,7 @@ static int load_group_database(Context *c) {
         return r;
 }
 
-static int make_backup(const char *target, const char *x) {
+static int make_backup(const char *target, const char *x, LabelContext *label_context) {
         _cleanup_(unlink_and_freep) char *dst_tmp = NULL;
         _cleanup_fclose_ FILE *dst = NULL;
         _cleanup_close_ int src = -EBADF;
@@ -325,11 +328,13 @@ static int make_backup(const char *target, const char *x) {
         if (fstat(src, &st) < 0)
                 return -errno;
 
-        r = fopen_temporary_label(
+        r = fopen_temporary_at_label(
+                        AT_FDCWD,
                         target,   /* The path for which to the look up the label */
                         x,        /* Where we want the file actually to end up */
                         &dst,     /* The temporary file we write to */
-                        &dst_tmp);
+                        &dst_tmp,
+                        label_context);
         if (r < 0)
                 return r;
 
@@ -527,7 +532,7 @@ static int write_temporary_passwd(
                 goto done;
         }
 
-        r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
+        r = fopen_temporary_at_label(AT_FDCWD, passwd_path, passwd_path, &passwd, &passwd_tmp, c->label_context);
         if (r < 0)
                 return log_debug_errno(r, "Failed to open temporary copy of %s: %m", passwd_path);
 
@@ -655,7 +660,7 @@ static int write_temporary_shadow(
                 goto done;
         }
 
-        r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
+        r = fopen_temporary_at_label(AT_FDCWD, shadow_path, shadow_path, &shadow, &shadow_tmp, c->label_context);
         if (r < 0)
                 return log_debug_errno(r, "Failed to open temporary copy of %s: %m", shadow_path);
 
@@ -792,7 +797,7 @@ static int write_temporary_group(
                 goto done;
         }
 
-        r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
+        r = fopen_temporary_at_label(AT_FDCWD, group_path, group_path, &group, &group_tmp, c->label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to open temporary copy of %s: %m", group_path);
 
@@ -911,7 +916,7 @@ static int write_temporary_gshadow(
                 goto done;
         }
 
-        r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
+        r = fopen_temporary_at_label(AT_FDCWD, gshadow_path, gshadow_path, &gshadow, &gshadow_tmp, c->label_context);
         if (r < 0)
                 return log_error_errno(r, "Failed to open temporary copy of %s: %m", gshadow_path);
 
@@ -1021,23 +1026,23 @@ static int write_files(Context *c) {
 
         /* Make a backup of the old files */
         if (group) {
-                r = make_backup("/etc/group", group_path);
+                r = make_backup(group_path, group_path, c->label_context);
                 if (r < 0)
                         return log_error_errno(r, "Failed to backup %s: %m", group_path);
         }
         if (gshadow) {
-                r = make_backup("/etc/gshadow", gshadow_path);
+                r = make_backup(gshadow_path, gshadow_path, c->label_context);
                 if (r < 0)
                         return log_error_errno(r, "Failed to backup %s: %m", gshadow_path);
         }
 
         if (passwd) {
-                r = make_backup("/etc/passwd", passwd_path);
+                r = make_backup(passwd_path, passwd_path, c->label_context);
                 if (r < 0)
                         return log_error_errno(r, "Failed to backup %s: %m", passwd_path);
         }
         if (shadow) {
-                r = make_backup("/etc/shadow", shadow_path);
+                r = make_backup(shadow_path, shadow_path, c->label_context);
                 if (r < 0)
                         return log_error_errno(r, "Failed to backup %s: %m", shadow_path);
         }
@@ -2351,6 +2356,10 @@ static int run(int argc, char *argv[]) {
                         return log_oom();
         }
 
+        r = mac_label_context_new(arg_root, &c.label_context);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
+
         /* Prepare to emit audit events, but only if we're operating on the host system. */
         if (!arg_root)
                 c.audit_fd = open_audit_fd_or_warn();
index 756c1458e36da6512eb6d1330a3f7f83e7f80095..d1d7c42ffafc8299b26d54c358356e3ff3b653fa 100644 (file)
@@ -232,6 +232,7 @@ static char *arg_root = NULL;
 static char *arg_image = NULL;
 static const char *arg_replace = NULL;
 static ImagePolicy *arg_image_policy = NULL;
+static LabelContext *arg_label_context = NULL;
 
 #define MAX_DEPTH 256
 
@@ -248,6 +249,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_label_context, mac_label_context_freep);
 
 static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
         [CREATION_NORMAL]   = "Created",
@@ -1062,7 +1064,7 @@ shortcut:
         }
 
         log_debug("Relabelling \"%s\"", path);
-        return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, /* flags= */ 0, /* label_context= */ NULL);
+        return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, /* flags= */ 0, arg_label_context);
 }
 
 static int path_open_parent_safe(const char *path, bool allow_failure) {
@@ -2070,7 +2072,7 @@ static int create_file(
                 return dir_fd;
 
         WITH_UMASK(0000) {
-                mac_selinux_create_file_prepare(path, S_IFREG, /* label_context= */ NULL);
+                mac_selinux_create_file_prepare(path, S_IFREG, arg_label_context);
                 fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_EXCL|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
                 mac_selinux_create_file_clear();
         }
@@ -2153,7 +2155,7 @@ static int truncate_file(
                 creation = CREATION_NORMAL; /* Didn't work without O_CREATE, try again with */
 
                 WITH_UMASK(0000) {
-                        mac_selinux_create_file_prepare(path, S_IFREG, /* label_context= */ NULL);
+                        mac_selinux_create_file_prepare(path, S_IFREG, arg_label_context);
                         fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
                         mac_selinux_create_file_clear();
                 }
@@ -2314,7 +2316,7 @@ static int create_directory_or_subvolume(
                 log_action("Would create", "Creating", "%s directory \"%s\"", path);
                 if (!arg_dry_run)
                         WITH_UMASK(0000)
-                                r = mkdirat_label(pfd, bn, mode, /* label_context= */ NULL);
+                                r = mkdirat_label(pfd, bn, mode, arg_label_context);
         }
 
         if (arg_dry_run)
@@ -2501,7 +2503,7 @@ static int create_device(
                 return dfd;
 
         WITH_UMASK(0000) {
-                mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL);
+                mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
                 r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
                 mac_selinux_create_file_clear();
         }
@@ -2532,7 +2534,7 @@ static int create_device(
                         fd = safe_close(fd);
 
                         WITH_UMASK(0000) {
-                                mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL);
+                                mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
                                 r = mknodat_atomic(dfd, bn, i->mode | file_type, i->major_minor);
                                 mac_selinux_create_file_clear();
                         }
@@ -2543,7 +2545,7 @@ static int create_device(
                                 if (r < 0)
                                         return log_error_errno(r, "rm -rf %s failed: %m", i->path);
 
-                                mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL);
+                                mac_selinux_create_file_prepare(i->path, file_type, arg_label_context);
                                 r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor));
                                 mac_selinux_create_file_clear();
                         }
@@ -2611,7 +2613,7 @@ static int create_fifo(Context *c, Item *i) {
                 return pfd;
 
         WITH_UMASK(0000) {
-                mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL);
+                mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
                 r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
                 mac_selinux_create_file_clear();
         }
@@ -2636,7 +2638,7 @@ static int create_fifo(Context *c, Item *i) {
                         fd = safe_close(fd);
 
                         WITH_UMASK(0000) {
-                                mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL);
+                                mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
                                 r = mkfifoat_atomic(pfd, bn, i->mode);
                                 mac_selinux_create_file_clear();
                         }
@@ -2645,7 +2647,7 @@ static int create_fifo(Context *c, Item *i) {
                                 if (r < 0)
                                         return log_error_errno(r, "rm -rf %s failed: %m", i->path);
 
-                                mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL);
+                                mac_selinux_create_file_prepare(i->path, S_IFIFO, arg_label_context);
                                 r = RET_NERRNO(mkfifoat(pfd, bn, i->mode));
                                 mac_selinux_create_file_clear();
                         }
@@ -2730,7 +2732,7 @@ static int create_symlink(Context *c, Item *i) {
         if (pfd < 0)
                 return pfd;
 
-        mac_selinux_create_file_prepare(i->path, S_IFLNK, /* label_context= */ NULL);
+        mac_selinux_create_file_prepare(i->path, S_IFLNK, arg_label_context);
         r = RET_NERRNO(symlinkat(i->argument, pfd, bn));
         mac_selinux_create_file_clear();
 
@@ -2766,13 +2768,13 @@ static int create_symlink(Context *c, Item *i) {
 
                 fd = safe_close(fd);
 
-                r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL);
+                r = symlinkat_atomic_full_label(i->argument, pfd, bn, SYMLINK_LABEL, arg_label_context);
                 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);
 
-                        r = symlinkat_atomic_full(i->argument, pfd, bn, SYMLINK_LABEL);
+                        r = symlinkat_atomic_full_label(i->argument, pfd, bn, SYMLINK_LABEL, arg_label_context);
                 }
                 if (r < 0)
                         return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
@@ -3060,7 +3062,7 @@ static int mkdir_parents_rm_if_wrong_type(mode_t child_mode, const char *path) {
                 if (r == -ENOENT) {
                         if (!arg_dry_run) {
                                 WITH_UMASK(0000)
-                                        r = mkdirat_label(parent_fd, t, 0755, /* label_context= */ NULL);
+                                        r = mkdirat_label(parent_fd, t, 0755, arg_label_context);
                                 if (r < 0) {
                                         _cleanup_free_ char *parent_name = NULL;
 
@@ -3101,7 +3103,7 @@ static int mkdir_parents_item(Item *i, mode_t child_mode) {
         } else
                 WITH_UMASK(0000)
                         if (!arg_dry_run)
-                                (void) mkdir_parents_label(i->path, 0755);
+                                (void) mkdirat_parents_label(AT_FDCWD, i->path, 0755, arg_label_context);
 
         return 0;
 }
@@ -4967,6 +4969,10 @@ static int run(int argc, char *argv[]) {
                         return log_oom();
         }
 
+        r = mac_label_context_new(arg_root, &arg_label_context);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize label context for root '%s': %m", arg_root);
+
         c.items = ordered_hashmap_new(&item_array_hash_ops);
         c.globs = ordered_hashmap_new(&item_array_hash_ops);
         if (!c.items || !c.globs)