From 6b0e3ea22251353a527bb749979b9c6033cdcdd9 Mon Sep 17 00:00:00 2001 From: Simon de Vlieger Date: Sat, 4 Jul 2026 12:36:11 +0200 Subject: [PATCH 1/4] label: plumb label_context through LabelOps SELinux labeling with --root/--image needs per-call context to carry an alternate policy database and root prefix. The current LabelOps interface has no way to pass this, forcing any solution to rely on global state. Add a LabelContext *label_context to the label_ops callbacks and all intermediate layers. Generic filesystem functions that most callers use (xopenat_full, write_string_file_full, etc.) get a _label variant carrying the extra parameter, with inline wrappers preserving the original signatures so the vast majority of call sites remain untouched. Signed-off-by: Simon de Vlieger --- src/basic/env-file.c | 8 +++---- src/basic/env-file.h | 5 ++++- src/basic/fileio.c | 18 +++++++++------- src/basic/fileio.h | 5 ++++- src/basic/forward.h | 1 + src/basic/fs-util.c | 25 ++++++++++----------- src/basic/fs-util.h | 20 +++++++++++++---- src/basic/label-util.c | 8 +++---- src/basic/label-util.h | 8 +++---- src/basic/mkdir.c | 43 +++++++++++++++++++------------------ src/basic/mkdir.h | 16 +++++++------- src/core/exec-credential.c | 4 ++-- src/core/namespace.c | 10 ++++----- src/core/socket.c | 2 +- src/firstboot/firstboot.c | 4 ++-- src/shared/copy.c | 10 ++++----- src/shared/dev-setup.c | 6 +++--- src/shared/discover-image.c | 2 +- src/shared/label-util.c | 17 ++++++++------- src/shared/label-util.h | 12 +++++------ src/shared/mkdir.c | 20 ++++++----------- src/shared/mkdir.h | 20 ++++++++++------- src/shared/mount-util.c | 2 +- src/shared/selinux-util.c | 12 ++++++----- src/shared/selinux-util.h | 8 +++---- src/shared/smack-util.c | 4 ++-- src/shared/tmpfile-util.c | 5 +++-- src/shared/tmpfile-util.h | 4 ++-- src/sysext/sysext.c | 8 +++---- src/test/test-label.c | 26 +++++++++++----------- src/test/test-selinux.c | 2 +- src/tmpfiles/tmpfiles.c | 24 ++++++++++----------- src/udev/udev-node.c | 2 +- 33 files changed, 192 insertions(+), 169 deletions(-) diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 7689c653a2..48f7cae60b 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -665,7 +665,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, WriteEnvFileFlags flags) { +int write_env_file_label(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags, LabelContext *label_context) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; int r; @@ -675,7 +675,7 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ bool call_label_ops_post = false; if (FLAGS_SET(flags, WRITE_ENV_FILE_LABEL)) { - r = label_ops_pre(dir_fd, fname, S_IFREG); + r = label_ops_pre(dir_fd, fname, S_IFREG, label_context); if (r < 0) return r; @@ -683,7 +683,7 @@ int write_env_file(int dir_fd, const char *fname, char **headers, char **l, Writ } r = fopen_tmpfile_linkable_at(dir_fd, fname, O_WRONLY|O_CLOEXEC, &p, &f); - int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f) : 0; + int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fname, /* created= */ !!f, label_context) : 0; if (r < 0) return r; CLEANUP_TMPFILE_AT(dir_fd, p); @@ -717,5 +717,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, WRITE_ENV_FILE_LABEL); + return write_env_file_label(dir_fd, fname, headers, l, WRITE_ENV_FILE_LABEL, /* label_context= */ NULL); } diff --git a/src/basic/env-file.h b/src/basic/env-file.h index 092b56a9a0..179652ad57 100644 --- a/src/basic/env-file.h +++ b/src/basic/env-file.h @@ -24,7 +24,10 @@ 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_env_file_label(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags, LabelContext *label_context); +static inline int write_env_file(int dir_fd, const char *fname, char **headers, char **l, WriteEnvFileFlags flags) { + return write_env_file_label(dir_fd, fname, headers, l, flags, /* label_context= */ NULL); +} int write_vconsole_conf(int dir_fd, const char *fname, char **l); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index d7b4a02cbb..028372c011 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -219,7 +219,8 @@ static int write_string_file_atomic_at( const char *fn, const char *line, WriteStringFileFlags flags, - const struct timespec *ts) { + const struct timespec *ts, + LabelContext *label_context) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; @@ -235,7 +236,7 @@ static int write_string_file_atomic_at( bool call_label_ops_post = false; if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) { - r = label_ops_pre(dir_fd, fn, mode); + r = label_ops_pre(dir_fd, fn, mode, label_context); if (r < 0) return r; @@ -243,7 +244,7 @@ static int write_string_file_atomic_at( } r = fopen_temporary_at(dir_fd, fn, &f, &p); - int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f) : 0; + int k = call_label_ops_post ? label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f, label_context) : 0; /* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures in * label_ops_post(). */ if (r < 0) @@ -276,13 +277,14 @@ static int write_string_file_atomic_at( return 0; } -int write_string_file_full( +int write_string_file_full_label( int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, - const char *label_fn) { + const char *label_fn, + LabelContext *label_context) { bool made_file = false; _cleanup_fclose_ FILE *f = NULL; @@ -307,7 +309,7 @@ int write_string_file_full( assert(fn); assert(flags & WRITE_STRING_FILE_CREATE); - r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts); + r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts, label_context); if (r < 0) goto fail; @@ -326,7 +328,7 @@ int write_string_file_full( bool call_label_ops_post = false; if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) { - r = label_ops_pre(dir_fd, label_fn ?: fn, mode); + r = label_ops_pre(dir_fd, label_fn ?: fn, mode, label_context); if (r < 0) goto fail; @@ -345,7 +347,7 @@ int write_string_file_full( if (call_label_ops_post) /* If openat_report_new() failed in the above, propagate the error code, and ignore * failures in label_ops_post(). */ - RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file)); + RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file, label_context)); } if (r < 0) goto fail; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 4910b28f9c..fa2123b76e 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -45,7 +45,10 @@ static inline int write_string_stream(FILE *f, const char *line, WriteStringFile return write_string_stream_full(f, line, flags, NULL); } -int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn); +int write_string_file_full_label(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn, LabelContext *label_context); +static inline int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn) { + return write_string_file_full_label(dir_fd, fn, line, flags, ts, label_fn, /* label_context= */ NULL); +} static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) { return write_string_file_full(dir_fd, fn, line, flags, NULL, NULL); } diff --git a/src/basic/forward.h b/src/basic/forward.h index f02801a77d..383cd5dbd2 100644 --- a/src/basic/forward.h +++ b/src/basic/forward.h @@ -128,6 +128,7 @@ typedef struct dual_timestamp dual_timestamp; typedef struct triple_timestamp triple_timestamp; typedef struct Compressor Compressor; typedef struct ConfFile ConfFile; +typedef struct LabelContext LabelContext; typedef struct LockFile LockFile; typedef struct PidRef PidRef; typedef struct Prioq Prioq; diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 76c55e30b6..d68a09814f 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -461,7 +461,7 @@ int symlinkat_idempotent(const char *target, int atfd, const char *linkpath, boo return 0; } -int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags) { +int symlinkat_atomic_full_label(const char *target, int atfd, const char *linkpath, SymlinkFlags flags, LabelContext *label_context) { int r; assert(target); @@ -483,7 +483,7 @@ int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, Sy bool call_label_ops_post = false; if (FLAGS_SET(flags, SYMLINK_LABEL)) { - r = label_ops_pre(atfd, linkpath, S_IFLNK); + r = label_ops_pre(atfd, linkpath, S_IFLNK, label_context); if (r < 0) return r; @@ -492,7 +492,7 @@ int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, Sy r = RET_NERRNO(symlinkat(target, atfd, t)); if (call_label_ops_post) - RET_GATHER(r, label_ops_post(atfd, t, /* created= */ r >= 0)); + RET_GATHER(r, label_ops_post(atfd, t, /* created= */ r >= 0, label_context)); if (r < 0) return r; @@ -1035,7 +1035,7 @@ int parse_cifs_service( return 0; } -int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode) { +int open_mkdir_at_full_label(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context) { _cleanup_close_ int fd = -EBADF, parent_fd = -EBADF; _cleanup_free_ char *fname = NULL, *parent = NULL; int r; @@ -1071,7 +1071,7 @@ int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_ path = fname; } - fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, xopen_flags, mode); + fd = xopenat_full_label(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, xopen_flags, mode, label_context); if (IN_SET(fd, -ELOOP, -ENOTDIR)) return -EEXIST; if (fd < 0) @@ -1171,7 +1171,7 @@ static int openat_with_automount(int dir_fd, const char *path, int open_flags, m return RET_NERRNO(openat(dir_fd, path, open_flags, mode)); } -int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) { +int xopenat_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context) { _cleanup_close_ int fd = -EBADF; bool made_dir = false, made_file = false; int r; @@ -1276,7 +1276,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_ bool call_label_ops_post = false; if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) { - r = label_ops_pre(dir_fd, path, FLAGS_SET(open_flags, O_DIRECTORY) ? S_IFDIR : S_IFREG); + r = label_ops_pre(dir_fd, path, FLAGS_SET(open_flags, O_DIRECTORY) ? S_IFDIR : S_IFREG, label_context); if (r < 0) return r; @@ -1433,7 +1433,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_ if (call_label_ops_post) { call_label_ops_post = false; - r = label_ops_post(fd, /* path= */ NULL, made_file || made_dir); + r = label_ops_post(fd, /* path= */ NULL, made_file || made_dir, label_context); if (r < 0) goto error; } @@ -1448,7 +1448,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_ error: if (call_label_ops_post) - (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : path, made_dir || made_file); + (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : path, made_dir || made_file, label_context); if (made_dir || made_file) (void) unlinkat(dir_fd, path, made_dir ? AT_REMOVEDIR : 0); @@ -1456,14 +1456,15 @@ error: return r; } -int xopenat_lock_full( +int xopenat_lock_full_label( int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, - int operation) { + int operation, + LabelContext *label_context) { _cleanup_close_ int fd = -EBADF; int r; @@ -1479,7 +1480,7 @@ int xopenat_lock_full( for (;;) { struct stat st; - fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode); + fd = xopenat_full_label(dir_fd, path, open_flags, xopen_flags, mode, label_context); if (fd < 0) return fd; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index bc33f2f8e9..b149290401 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -58,7 +58,10 @@ typedef enum SymlinkFlags { SYMLINK_LABEL = 1 << 1, } SymlinkFlags; -int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags); +int symlinkat_atomic_full_label(const char *target, int atfd, const char *linkpath, SymlinkFlags flags, LabelContext *label_context); +static inline int symlinkat_atomic_full(const char *target, int atfd, const char *linkpath, SymlinkFlags flags) { + return symlinkat_atomic_full_label(target, atfd, linkpath, flags, /* label_context= */ NULL); +} static inline int symlink_atomic(const char *target, const char *linkpath) { return symlinkat_atomic_full(target, AT_FDCWD, linkpath, 0); } @@ -119,7 +122,10 @@ typedef enum XOpenFlags { XO_AUTO_RW_RO = 1 << 7, /* Open in O_RDWR mode if possible, O_RDONLY if not */ } XOpenFlags; -int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode); +int open_mkdir_at_full_label(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context); +static inline int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode) { + return open_mkdir_at_full_label(dirfd, path, flags, xopen_flags, mode, /* label_context= */ NULL); +} static inline int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) { return open_mkdir_at_full(dirfd, path, flags, 0, mode); } @@ -129,12 +135,18 @@ static inline int open_mkdir(const char *path, int flags, mode_t mode) { int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created); -int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode); +int xopenat_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LabelContext *label_context); +static inline int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) { + return xopenat_full_label(dir_fd, path, open_flags, xopen_flags, mode, /* label_context= */ NULL); +} static inline int xopenat(int dir_fd, const char *path, int open_flags) { return xopenat_full(dir_fd, path, open_flags, 0, MODE_INVALID); } -int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation); +int xopenat_lock_full_label(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation, LabelContext *label_context); +static inline int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation) { + return xopenat_lock_full_label(dir_fd, path, open_flags, xopen_flags, mode, locktype, operation, /* label_context= */ NULL); +} static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) { return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation); } diff --git a/src/basic/label-util.c b/src/basic/label-util.c index a6d616210a..4b1b3b9dfd 100644 --- a/src/basic/label-util.c +++ b/src/basic/label-util.c @@ -18,16 +18,16 @@ void label_ops_reset(void) { label_ops = NULL; } -int label_ops_pre(int dir_fd, const char *path, mode_t mode) { +int label_ops_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { if (!label_ops || !label_ops->pre) return 0; - return label_ops->pre(dir_fd, path, mode); + return label_ops->pre(dir_fd, path, mode, label_context); } -int label_ops_post(int dir_fd, const char *path, bool created) { +int label_ops_post(int dir_fd, const char *path, bool created, LabelContext *label_context) { if (!label_ops || !label_ops->post) return 0; - return label_ops->post(dir_fd, path, created); + return label_ops->post(dir_fd, path, created, label_context); } diff --git a/src/basic/label-util.h b/src/basic/label-util.h index 186f93d697..efa06396cb 100644 --- a/src/basic/label-util.h +++ b/src/basic/label-util.h @@ -4,12 +4,12 @@ #include "forward.h" typedef struct LabelOps { - int (*pre)(int dir_fd, const char *path, mode_t mode); - int (*post)(int dir_fd, const char *path, bool created); + int (*pre)(int dir_fd, const char *path, mode_t mode, LabelContext *label_context); + int (*post)(int dir_fd, const char *path, bool created, LabelContext *label_context); } LabelOps; int label_ops_set(const LabelOps *label_ops); void label_ops_reset(void); -int label_ops_pre(int dir_fd, const char *path, mode_t mode); -int label_ops_post(int dir_fd, const char *path, bool created); +int label_ops_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context); +int label_ops_post(int dir_fd, const char *path, bool created, LabelContext *label_context); diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index fc79763bb9..188703763c 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -25,16 +25,17 @@ int mkdirat_safe_internal( uid_t uid, gid_t gid, MkdirFlags flags, - mkdirat_func_t _mkdirat) { + mkdirat_func_t _mkdirat, + LabelContext *label_context) { struct stat st; int r; assert(path); assert(mode != MODE_INVALID); - assert(_mkdirat && _mkdirat != mkdirat); + assert(_mkdirat); - r = _mkdirat(dir_fd, path, mode); + r = _mkdirat(dir_fd, path, mode, label_context); if (r >= 0) return chmod_and_chown_at(dir_fd, path, mode, uid, gid); if (r != -EEXIST) @@ -52,7 +53,7 @@ int mkdirat_safe_internal( if (r == 0) return mkdirat_safe_internal(dir_fd, p, mode, uid, gid, flags & ~MKDIR_FOLLOW_SYMLINK, - _mkdirat); + _mkdirat, label_context); if (fstatat(dir_fd, p, &st, AT_SYMLINK_NOFOLLOW) < 0) return -errno; @@ -80,20 +81,20 @@ int mkdirat_safe_internal( return 0; } -int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) { +int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode, LabelContext *label_context) { return RET_NERRNO(mkdirat(dirfd, pathname, mode)); } int mkdirat_safe(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_errno_wrapper); + return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL); } -int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) { +int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) { const char *e = NULL; int r; assert(path); - assert(_mkdirat != mkdirat); + assert(_mkdirat); if (isempty(path)) return 0; @@ -134,7 +135,7 @@ int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t ui s[n] = '\0'; - r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat); + r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat, label_context); if (r < 0 && r != -EEXIST) return r; @@ -142,12 +143,12 @@ int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t ui } } -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) { +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) { _cleanup_close_ int fd = AT_FDCWD; const char *p; assert(path); - assert(_mkdirat != mkdirat); + assert(_mkdirat); if (prefix) { p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT); @@ -160,34 +161,34 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui } else p = path; - return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat); + return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat, label_context); } int mkdirat_parents(int dir_fd, const char *path, mode_t mode) { - return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper); + return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper, /* label_context= */ NULL); } int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper); + return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL); } -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) { +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context) { int r; /* Like mkdir -p */ - assert(_mkdirat != mkdirat); + assert(_mkdirat); - r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat); + r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat, label_context); if (r < 0) return r; if (!uid_is_valid(uid) && !gid_is_valid(gid) && flags == 0) { - r = _mkdirat(AT_FDCWD, path, mode); + r = _mkdirat(AT_FDCWD, path, mode, label_context); if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0)) return r; } else { - r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat); + r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat, label_context); if (r < 0 && r != -EEXIST) return r; } @@ -196,11 +197,11 @@ int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t ui } int mkdir_p(const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper); + return mkdir_p_internal(/* prefix= */ NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper, /* label_context= */ NULL); } int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper); + return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper, /* label_context= */ NULL); } int mkdir_p_root_full(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, usec_t ts, Hashmap *subvolumes) { diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index d18b3bfe49..55860572a8 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -9,7 +9,7 @@ typedef enum MkdirFlags { MKDIR_WARN_MODE = 1 << 2, /* Log at LOG_WARNING when mode doesn't match */ } MkdirFlags; -int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode); +int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode, LabelContext *label_context); int mkdirat_safe(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); static inline int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { @@ -28,11 +28,11 @@ static inline int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t } /* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */ -typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode); -int mkdirat_safe_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir); -static inline int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir) { - return mkdirat_safe_internal(AT_FDCWD, path, mode, uid, gid, flags, _mkdir); +typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode, LabelContext *label_context); +int mkdirat_safe_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context); +static inline int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context) { + return mkdirat_safe_internal(AT_FDCWD, path, mode, uid, gid, flags, _mkdir, label_context); } -int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat); -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir); -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir); +int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat, LabelContext *label_context); +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context); +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdir, LabelContext *label_context); diff --git a/src/core/exec-credential.c b/src/core/exec-credential.c index 0cd7dd25d7..5b6bd943cd 100644 --- a/src/core/exec-credential.c +++ b/src/core/exec-credential.c @@ -982,7 +982,7 @@ static int setup_credentials_plain_dir( return log_debug_errno(dfd, "Failed to create workspace for credentials: %m"); workspace_rm = workspace; - (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0); + (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0, /* label_context= */ NULL); r = acquire_credentials(context, dfd, /* ownership_ok= */ false); if (r < 0) @@ -1063,7 +1063,7 @@ static int setup_credentials_internal( if (dfd < 0) return dfd; - (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0); + (void) label_fix_full(dfd, /* inode_path= */ NULL, cred_dir, /* flags= */ 0, /* label_context= */ NULL); r = acquire_credentials(context, dfd, /* ownership_ok= */ true); if (r < 0) diff --git a/src/core/namespace.c b/src/core/namespace.c index 1a15e79901..45253b4804 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1220,7 +1220,7 @@ static int clone_device_node(const char *node, const char *temporary_mount, bool /* First, try to create device node properly */ if (*make_devnode) { - mac_selinux_create_file_prepare(node, st.st_mode); + mac_selinux_create_file_prepare(node, st.st_mode, /* label_context= */ NULL); r = mknod(dn, st.st_mode, st.st_rdev); mac_selinux_create_file_clear(); if (r >= 0) @@ -1341,7 +1341,7 @@ static int mount_private_dev(const MountEntry *m, const NamespaceParameters *p) if (r < 0) return r; - r = label_fix_full(AT_FDCWD, dev, "/dev", 0); + r = label_fix_full(AT_FDCWD, dev, "/dev", /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_debug_errno(r, "Failed to fix label of '%s' as /dev/: %m", dev); @@ -1610,7 +1610,7 @@ static int mount_tmpfs(const MountEntry *m) { if (r < 0) return r; - r = label_fix_full(AT_FDCWD, entry_path, inner_path, 0); + r = label_fix_full(AT_FDCWD, entry_path, inner_path, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_debug_errno(r, "Failed to fix label of '%s' as '%s': %m", entry_path, inner_path); @@ -2067,7 +2067,7 @@ static int apply_one_mount( if (r < 0) return log_debug_errno(r, "Failed to create source directory %s: %m", mount_entry_source(m)); - r = label_fix_full(AT_FDCWD, mount_entry_source(m), mount_entry_unprefixed_path(m), /* flags= */ 0); + r = label_fix_full(AT_FDCWD, mount_entry_source(m), mount_entry_unprefixed_path(m), /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_error_errno(r, "Failed to set label of the source directory %s: %m", mount_entry_source(m)); } @@ -3474,7 +3474,7 @@ int setup_tmp_dir_one(const char *id, const char *prefix, char **ret_path) { return r; } - r = label_fix_full(AT_FDCWD, inner_dir, prefix, 0); + r = label_fix_full(AT_FDCWD, inner_dir, prefix, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) { (void) rmdir(inner_dir); (void) rmdir(d); diff --git a/src/core/socket.c b/src/core/socket.c index a7aa34caeb..76cd1ce043 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1209,7 +1209,7 @@ static int fifo_address_create( (void) mkdir_parents_label(path, directory_mode); - r = mac_selinux_create_file_prepare(path, S_IFIFO); + r = mac_selinux_create_file_prepare(path, S_IFIFO, /* label_context= */ NULL); if (r < 0) return r; diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 5ebaf89764..ed6817a186 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -1038,7 +1038,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); + r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp, /* label_context= */ NULL); if (r < 0) return r; @@ -1109,7 +1109,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); + r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp, /* label_context= */ NULL); if (r < 0) return r; diff --git a/src/shared/copy.c b/src/shared/copy.c index 208e3fd52d..96a9e99a19 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -480,7 +480,7 @@ static int fd_copy_symlink( return r; if (copy_flags & COPY_MAC_CREATE) { - r = mac_selinux_create_file_prepare_at(dt, to, S_IFLNK); + r = mac_selinux_create_file_prepare_at(dt, to, S_IFLNK, /* label_context= */ NULL); if (r < 0) return r; } @@ -836,7 +836,7 @@ static int fd_copy_regular( return fdf; if (copy_flags & COPY_MAC_CREATE) { - r = mac_selinux_create_file_prepare_at(dt, to, S_IFREG); + r = mac_selinux_create_file_prepare_at(dt, to, S_IFREG, /* label_context= */ NULL); if (r < 0) return r; } @@ -923,7 +923,7 @@ static int fd_copy_fifo( return 0; if (copy_flags & COPY_MAC_CREATE) { - r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO); + r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO, /* label_context= */ NULL); if (r < 0) return r; } @@ -976,7 +976,7 @@ static int fd_copy_node( return 0; if (copy_flags & COPY_MAC_CREATE) { - r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT); + r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT, /* label_context= */ NULL); if (r < 0) return r; } @@ -1577,7 +1577,7 @@ int copy_file_atomic_at_full( assert(!FLAGS_SET(copy_flags, COPY_LOCK_BSD)); if (copy_flags & COPY_MAC_CREATE) { - r = mac_selinux_create_file_prepare_at(dir_fdt, to, S_IFREG); + r = mac_selinux_create_file_prepare_at(dir_fdt, to, S_IFREG, /* label_context= */ NULL); if (r < 0) return r; } diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index 9424e22001..9cff48f3fb 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -46,7 +46,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) { } else n = k; - r = symlink_label(j, n); + r = symlink_label(j, n, /* label_context= */ NULL); if (r < 0) log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n); @@ -113,9 +113,9 @@ int make_inaccessible_nodes( return log_oom(); if (S_ISDIR(inode_type)) - r = mkdirat_label(inaccessible_fd, fn, 0000); + r = mkdirat_label(inaccessible_fd, fn, 0000, /* label_context= */ NULL); else - r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0)); + r = mknodat_label(inaccessible_fd, fn, inode_type | 0000, makedev(0, 0), /* label_context= */ NULL); if (r == -EEXIST) { if (fchmodat(inaccessible_fd, fn, 0000, AT_SYMLINK_NOFOLLOW) < 0) log_debug_errno(errno, "Failed to adjust access mode of existing inode '%s', ignoring: %m", path); diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 99c5365a89..a8246e3b54 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -2199,7 +2199,7 @@ int image_setup_pool(RuntimeScope scope, ImageClass class, bool use_btrfs_subvol if (!use_btrfs_subvol) return 0; - (void) btrfs_subvol_make_label(pool); + (void) btrfs_subvol_make_label(pool, /* label_context= */ NULL); if (!use_btrfs_quota) return 0; diff --git a/src/shared/label-util.c b/src/shared/label-util.c index 6c6e73bab3..2ffb43f88e 100644 --- a/src/shared/label-util.c +++ b/src/shared/label-util.c @@ -13,7 +13,8 @@ int label_fix_full( int atfd, const char *inode_path, /* path of inode to apply label to */ const char *label_path, /* path to use as database lookup key in label database (typically same as inode_path, but not always) */ - LabelFixFlags flags) { + LabelFixFlags flags, + LabelContext *label_context) { int r, q; @@ -30,7 +31,7 @@ int label_fix_full( * If atfd is AT_FDCWD then we'll operate on the inode the path refers to. */ - r = mac_selinux_fix_full(atfd, inode_path, label_path, flags); + r = mac_selinux_fix_full(atfd, inode_path, label_path, flags, label_context); q = mac_smack_fix_full(atfd, inode_path, label_path, flags); if (r < 0) return r; @@ -40,13 +41,13 @@ int label_fix_full( return 0; } -int symlink_label(const char *old_path, const char *new_path) { +int symlink_label(const char *old_path, const char *new_path, LabelContext *label_context) { int r; assert(old_path); assert(new_path); - r = mac_selinux_create_file_prepare(new_path, S_IFLNK); + r = mac_selinux_create_file_prepare(new_path, S_IFLNK, label_context); if (r < 0) return r; @@ -59,13 +60,13 @@ int symlink_label(const char *old_path, const char *new_path) { return mac_smack_fix(new_path, 0); } -int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev) { +int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev, LabelContext *label_context) { int r; assert(dirfd >= 0 || dirfd == AT_FDCWD); assert(pathname); - r = mac_selinux_create_file_prepare_at(dirfd, pathname, mode); + r = mac_selinux_create_file_prepare_at(dirfd, pathname, mode, label_context); if (r < 0) return r; @@ -78,12 +79,12 @@ int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev) { return mac_smack_fix_full(dirfd, pathname, NULL, 0); } -int btrfs_subvol_make_label(const char *path) { +int btrfs_subvol_make_label(const char *path, LabelContext *label_context) { int r; assert(path); - r = mac_selinux_create_file_prepare(path, S_IFDIR); + r = mac_selinux_create_file_prepare(path, S_IFDIR, label_context); if (r < 0) return r; diff --git a/src/shared/label-util.h b/src/shared/label-util.h index 7420b9f149..ea8c2b7165 100644 --- a/src/shared/label-util.h +++ b/src/shared/label-util.h @@ -10,20 +10,20 @@ typedef enum LabelFixFlags { LABEL_IGNORE_EROFS = 1 << 1, } LabelFixFlags; -int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags); +int label_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags, LabelContext *label_context); static inline int label_fix(const char *path, LabelFixFlags flags) { - return label_fix_full(AT_FDCWD, path, path, flags); + return label_fix_full(AT_FDCWD, path, path, flags, /* label_context= */ NULL); } -int symlink_label(const char *old_path, const char *new_path); +int symlink_label(const char *old_path, const char *new_path, LabelContext *label_context); -int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev); +int mknodat_label(int dirfd, const char *pathname, mode_t mode, dev_t dev, LabelContext *label_context); static inline int mknod_label(const char *pathname, mode_t mode, dev_t dev) { - return mknodat_label(AT_FDCWD, pathname, mode, dev); + return mknodat_label(AT_FDCWD, pathname, mode, dev, /* label_context= */ NULL); } -int btrfs_subvol_make_label(const char *path); +int btrfs_subvol_make_label(const char *path, LabelContext *label_context); int mac_init(void); int mac_init_lazy(void); diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c index 1228bca19b..f90403275d 100644 --- a/src/shared/mkdir.c +++ b/src/shared/mkdir.c @@ -8,12 +8,12 @@ #include "selinux-util.h" #include "smack-util.h" -int mkdirat_label(int dirfd, const char *path, mode_t mode) { +int mkdirat_label(int dirfd, const char *path, mode_t mode, LabelContext *label_context) { int r; assert(path); - r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR); + r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR, label_context); if (r < 0) return r; @@ -25,18 +25,10 @@ int mkdirat_label(int dirfd, const char *path, mode_t mode) { return mac_smack_fix_full(dirfd, path, NULL, 0); } -int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_label); +int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, LabelContext *label_context) { + return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_label, label_context); } -int mkdirat_parents_label(int dir_fd, const char *path, mode_t mode) { - return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label); -} - -int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_label); -} - -int mkdir_p_label(const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label); +int mkdirat_parents_label(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { + return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label, label_context); } diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h index e20b020c94..080b085062 100644 --- a/src/shared/mkdir.h +++ b/src/shared/mkdir.h @@ -5,21 +5,25 @@ #include "../basic/mkdir.h" /* IWYU pragma: export */ -int mkdirat_label(int dirfd, const char *path, mode_t mode); +int mkdirat_label(int dirfd, const char *path, mode_t mode, LabelContext *label_context); static inline int mkdir_label(const char *path, mode_t mode) { - return mkdirat_label(AT_FDCWD, path, mode); + return mkdirat_label(AT_FDCWD, path, mode, /* label_context= */ NULL); } -int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); +int mkdirat_safe_label(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, LabelContext *label_context); static inline int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { - return mkdirat_safe_label(AT_FDCWD, path, mode, uid, gid, flags); + return mkdirat_safe_label(AT_FDCWD, path, mode, uid, gid, flags, /* label_context= */ NULL); } -int mkdirat_parents_label(int dir_fd, const char *path, mode_t mod); +int mkdirat_parents_label(int dir_fd, const char *path, mode_t mod, LabelContext *label_context); static inline int mkdir_parents_label(const char *path, mode_t mod) { - return mkdirat_parents_label(AT_FDCWD, path, mod); + return mkdirat_parents_label(AT_FDCWD, path, mod, /* label_context= */ NULL); } -int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); +static inline int mkdir_parents_safe_label(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { + return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_label, /* label_context= */ NULL); +} -int mkdir_p_label(const char *path, mode_t mode); +static inline int mkdir_p_label(const char *path, mode_t mode) { + return mkdir_p_internal(/* prefix= */ NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_label, /* label_context= */ NULL); +} diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index 17c43420e6..1d2cfc2f21 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -1946,7 +1946,7 @@ int make_mount_point_inode_from_mode(int dir_fd, const char *dest, mode_t source assert(dest); if (S_ISDIR(source_mode)) - return mkdirat_label(dir_fd, dest, target_mode & 07777); + return mkdirat_label(dir_fd, dest, target_mode & 07777, /* label_context= */ NULL); else return RET_NERRNO(mknodat(dir_fd, dest, S_IFREG|(target_mode & 07666), 0)); /* Mask off X bit */ } diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index 15d9f2fddb..f275db1c81 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -43,11 +43,11 @@ static int last_policyload = 0; static struct selabel_handle *label_hnd = NULL; static bool have_status_page = false; -static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode) { - return mac_selinux_create_file_prepare_at(dir_fd, path, mode); +static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { + return mac_selinux_create_file_prepare_at(dir_fd, path, mode, label_context); } -static int mac_selinux_label_post(int dir_fd, const char *path, bool created) { +static int mac_selinux_label_post(int dir_fd, const char *path, bool created, LabelContext *label_context) { mac_selinux_create_file_clear(); return 0; } @@ -421,7 +421,8 @@ int mac_selinux_fix_full( int atfd, const char *inode_path, const char *label_path, - LabelFixFlags flags) { + LabelFixFlags flags, + LabelContext *label_context) { assert(atfd >= 0 || atfd == AT_FDCWD); assert(atfd >= 0 || inode_path); @@ -694,7 +695,8 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) int mac_selinux_create_file_prepare_at( int dir_fd, const char *path, - mode_t mode) { + mode_t mode, + LabelContext *label_context) { #if HAVE_SELINUX _cleanup_free_ char *abspath = NULL; diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h index d361963344..06bae27446 100644 --- a/src/shared/selinux-util.h +++ b/src/shared/selinux-util.h @@ -93,7 +93,7 @@ void mac_selinux_finish(void); void mac_selinux_disable_logging(void); -int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags); +int mac_selinux_fix_full(int atfd, const char *inode_path, const char *label_path, LabelFixFlags flags, LabelContext *label_context); int mac_selinux_apply(const char *path, const char *label); int mac_selinux_apply_fd(int fd, const char *path, const char *label); @@ -103,9 +103,9 @@ int mac_selinux_get_our_label(char **ret_label); int mac_selinux_get_peer_label(int socket_fd, char **ret_label); int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **ret_label); -int mac_selinux_create_file_prepare_at(int dir_fd, const char *path, mode_t mode); -static inline int mac_selinux_create_file_prepare(const char *path, mode_t mode) { - return mac_selinux_create_file_prepare_at(AT_FDCWD, path, mode); +int mac_selinux_create_file_prepare_at(int dir_fd, const char *path, mode_t mode, LabelContext *label_context); +static inline int mac_selinux_create_file_prepare(const char *path, mode_t mode, LabelContext *label_context) { + return mac_selinux_create_file_prepare_at(AT_FDCWD, path, mode, label_context); } int mac_selinux_create_file_prepare_label(const char *path, const char *label); void mac_selinux_create_file_clear(void); diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c index 6380a4e3af..79aa12cb36 100644 --- a/src/shared/smack-util.c +++ b/src/shared/smack-util.c @@ -221,11 +221,11 @@ int renameat_and_apply_smack_floor_label(int fdf, const char *from, int fdt, con #endif } -static int mac_smack_label_pre(int dir_fd, const char *path, mode_t mode) { +static int mac_smack_label_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { return 0; } -static int mac_smack_label_post(int dir_fd, const char *path, bool created) { +static int mac_smack_label_post(int dir_fd, const char *path, bool created, LabelContext *label_context) { if (!created) return 0; diff --git a/src/shared/tmpfile-util.c b/src/shared/tmpfile-util.c index 9a5360d6d2..d29a2c321d 100644 --- a/src/shared/tmpfile-util.c +++ b/src/shared/tmpfile-util.c @@ -10,14 +10,15 @@ int fopen_temporary_at_label( const char *target, const char *path, FILE **f, - char **temp_path) { + char **temp_path, + LabelContext *label_context) { int r; assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(path); - r = mac_selinux_create_file_prepare_at(dir_fd, target, S_IFREG); + r = mac_selinux_create_file_prepare_at(dir_fd, target, S_IFREG, label_context); if (r < 0) return r; diff --git a/src/shared/tmpfile-util.h b/src/shared/tmpfile-util.h index 23db87cbb1..8e821fae67 100644 --- a/src/shared/tmpfile-util.h +++ b/src/shared/tmpfile-util.h @@ -7,7 +7,7 @@ * Targets that link libshared automatically pick up this version via -Isrc/shared; targets that only have * src/basic on their include path fall through to the basic header. */ -int fopen_temporary_at_label(int dir_fd, const char *target, const char *path, FILE **f, char **temp_path); +int fopen_temporary_at_label(int dir_fd, const char *target, const char *path, FILE **f, char **temp_path, LabelContext *label_context); static inline int fopen_temporary_label(const char *target, const char *path, FILE **f, char **temp_path) { - return fopen_temporary_at_label(AT_FDCWD, target, path, f, temp_path); + return fopen_temporary_at_label(AT_FDCWD, target, path, f, temp_path, /* label_context= */ NULL); } diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 986c0b51e9..7b4dee1bba 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -998,7 +998,7 @@ static int resolve_mutable_directory( if (fchmod(chmod_fd, hierarchy_mode) < 0) return log_error_errno(errno, "Failed to chmod directory '%s/%s': %m", strempty(root), skip_leading_slash(path)); - r = mac_selinux_fix_full(chmod_fd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0); + r = mac_selinux_fix_full(chmod_fd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_error_errno(r, "Failed to fix SELinux label for '%s/%s': %m", strempty(root), skip_leading_slash(path)); } @@ -1376,7 +1376,7 @@ static int mount_overlayfs_with_op( if (atfd < 0) return log_error_errno(errno, "Failed to open directory '%s': %m", meta_path); - r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0); + r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", meta_path); @@ -1389,7 +1389,7 @@ static int mount_overlayfs_with_op( if (dfd < 0) return log_error_errno(errno, "Failed to open directory '%s': %m", op->work_dir); - r = mac_selinux_fix_full(dfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0); + r = mac_selinux_fix_full(dfd, /* inode_path= */ NULL, op->hierarchy, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", op->work_dir); @@ -1601,7 +1601,7 @@ static int store_info_in_meta( if (atfd < 0) return log_error_errno(errno, "Failed to open directory '%s': %m", f); - r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0); + r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0, /* label_context= */ NULL); if (r < 0) return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", hierarchy); diff --git a/src/test/test-label.c b/src/test/test-label.c index 3bd96a3a1b..a2df754ef8 100644 --- a/src/test/test-label.c +++ b/src/test/test-label.c @@ -30,7 +30,7 @@ static int check_path(int dir_fd, const char *path) { return 0; } -static int pre_labelling_func(int dir_fd, const char *path, mode_t mode) { +static int pre_labelling_func(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { int r; assert(mode != MODE_INVALID); @@ -41,7 +41,7 @@ static int pre_labelling_func(int dir_fd, const char *path, mode_t mode) { return 0; } -static int post_labelling_func(int dir_fd, const char *path, bool created) { +static int post_labelling_func(int dir_fd, const char *path, bool created, LabelContext *label_context) { int r; /* assume label policies that restrict certain labels */ @@ -115,11 +115,11 @@ TEST(label_ops_pre) { label_ops_reset(); label_ops_set(&test_label_ops); fd = get_dir_fd("file1.txt", 0755); - assert_se(label_ops_pre(fd, "file1.txt", 0644) == 0); - assert_se(label_ops_pre(fd, "/restricted_directory", 0644) == -EACCES); - assert_se(label_ops_pre(fd, "", 0700) == -EINVAL); - assert_se(label_ops_pre(fd, "/tmp", 0700) == 0); - assert_se(label_ops_pre(fd, "wekrgoierhgoierhqgherhgwklegnlweehgorwfkryrit", 0644) == -ENAMETOOLONG); + assert_se(label_ops_pre(fd, "file1.txt", 0644, /* label_context= */ NULL) == 0); + assert_se(label_ops_pre(fd, "/restricted_directory", 0644, /* label_context= */ NULL) == -EACCES); + assert_se(label_ops_pre(fd, "", 0700, /* label_context= */ NULL) == -EINVAL); + assert_se(label_ops_pre(fd, "/tmp", 0700, /* label_context= */ NULL) == 0); + assert_se(label_ops_pre(fd, "wekrgoierhgoierhqgherhgwklegnlweehgorwfkryrit", 0644, /* label_context= */ NULL) == -ENAMETOOLONG); } TEST(label_ops_post) { @@ -138,17 +138,17 @@ TEST(label_ops_post) { text1 = "Add initial texts to file for testing label operations to file1\n"; assert_se(labelling_op(fd, text1, "file1.txt", 0644) == 0); - assert_se(label_ops_post(fd, "file1.txt", true) == 0); + assert_se(label_ops_post(fd, "file1.txt", true, /* label_context= */ NULL) == 0); assert_se(strlen(text1) == (size_t)buf.st_size); text2 = "Add text2 data to file2\n"; assert_se(labelling_op(fd, text2, "file2.txt", 0644) == 0); - assert_se(label_ops_post(fd, "file2.txt", true) == 0); + assert_se(label_ops_post(fd, "file2.txt", true, /* label_context= */ NULL) == 0); assert_se(strlen(text2) == (size_t)buf.st_size); - assert_se(label_ops_post(fd, "file3.txt", true) == -ENOENT); - assert_se(label_ops_post(fd, "/abcd", true) == -ENOENT); - assert_se(label_ops_post(fd, "/restricted_directory", true) == -EACCES); - assert_se(label_ops_post(fd, "", true) == -EINVAL); + assert_se(label_ops_post(fd, "file3.txt", true, /* label_context= */ NULL) == -ENOENT); + assert_se(label_ops_post(fd, "/abcd", true, /* label_context= */ NULL) == -ENOENT); + assert_se(label_ops_post(fd, "/restricted_directory", true, /* label_context= */ NULL) == -EACCES); + assert_se(label_ops_post(fd, "", true, /* label_context= */ NULL) == -EINVAL); } DEFINE_TEST_MAIN(LOG_INFO) diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c index 93e30896b7..f2ad6e6a3e 100644 --- a/src/test/test-selinux.c +++ b/src/test/test-selinux.c @@ -84,7 +84,7 @@ static void test_create_file_prepare(const char* fname) { log_info("============ %s ==========", __func__); - r = mac_selinux_create_file_prepare(fname, S_IRWXU); + r = mac_selinux_create_file_prepare(fname, S_IRWXU, /* label_context= */ NULL); log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r); mac_selinux_create_file_clear(); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 28a4c9a987..756c1458e3 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1062,7 +1062,7 @@ shortcut: } log_debug("Relabelling \"%s\"", path); - return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0); + return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, /* flags= */ 0, /* label_context= */ NULL); } static int path_open_parent_safe(const char *path, bool allow_failure) { @@ -2070,7 +2070,7 @@ static int create_file( return dir_fd; WITH_UMASK(0000) { - mac_selinux_create_file_prepare(path, S_IFREG); + mac_selinux_create_file_prepare(path, S_IFREG, /* label_context= */ NULL); 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 +2153,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); + mac_selinux_create_file_prepare(path, S_IFREG, /* label_context= */ NULL); 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 +2314,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); + r = mkdirat_label(pfd, bn, mode, /* label_context= */ NULL); } if (arg_dry_run) @@ -2501,7 +2501,7 @@ static int create_device( return dfd; WITH_UMASK(0000) { - mac_selinux_create_file_prepare(i->path, file_type); + mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL); r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor)); mac_selinux_create_file_clear(); } @@ -2532,7 +2532,7 @@ static int create_device( fd = safe_close(fd); WITH_UMASK(0000) { - mac_selinux_create_file_prepare(i->path, file_type); + mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL); r = mknodat_atomic(dfd, bn, i->mode | file_type, i->major_minor); mac_selinux_create_file_clear(); } @@ -2543,7 +2543,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); + mac_selinux_create_file_prepare(i->path, file_type, /* label_context= */ NULL); r = RET_NERRNO(mknodat(dfd, bn, i->mode | file_type, i->major_minor)); mac_selinux_create_file_clear(); } @@ -2611,7 +2611,7 @@ static int create_fifo(Context *c, Item *i) { return pfd; WITH_UMASK(0000) { - mac_selinux_create_file_prepare(i->path, S_IFIFO); + mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL); r = RET_NERRNO(mkfifoat(pfd, bn, i->mode)); mac_selinux_create_file_clear(); } @@ -2636,7 +2636,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); + mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL); r = mkfifoat_atomic(pfd, bn, i->mode); mac_selinux_create_file_clear(); } @@ -2645,7 +2645,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); + mac_selinux_create_file_prepare(i->path, S_IFIFO, /* label_context= */ NULL); r = RET_NERRNO(mkfifoat(pfd, bn, i->mode)); mac_selinux_create_file_clear(); } @@ -2730,7 +2730,7 @@ static int create_symlink(Context *c, Item *i) { if (pfd < 0) return pfd; - mac_selinux_create_file_prepare(i->path, S_IFLNK); + mac_selinux_create_file_prepare(i->path, S_IFLNK, /* label_context= */ NULL); r = RET_NERRNO(symlinkat(i->argument, pfd, bn)); mac_selinux_create_file_clear(); @@ -3060,7 +3060,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); + r = mkdirat_label(parent_fd, t, 0755, /* label_context= */ NULL); if (r < 0) { _cleanup_free_ char *parent_name = NULL; diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index ba28a8b809..09154c8895 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -683,7 +683,7 @@ static int udev_node_apply_permissions_impl( /* set the defaults */ if (!selinux) - (void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT); + (void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT, /* label_context= */ NULL); if (!smack) (void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL); } From f2b82e5c20f9d1585a0fea140806f19ac694c18c Mon Sep 17 00:00:00 2001 From: Simon de Vlieger Date: Sat, 4 Jul 2026 12:41:20 +0200 Subject: [PATCH 2/4] selinux: add LabelContext for alternate-root labeling When operating on an alternate root (--root/--image), SELinux labels must come from that root's policy, not the host's. This requires opening a separate selabel_handle against the target's policy database and remembering the root path for prefix stripping. Introduce LabelContext to carry both, and mac_label_context_new() to set it up: it reads the target's SELinux config, validates SELINUXTYPE to prevent path traversal, sets the policy root, and opens a label database scoped to the target image. Signed-off-by: Simon de Vlieger --- src/shared/label-util.c | 16 +++ src/shared/label-util.h | 4 + src/shared/selinux-util.c | 215 ++++++++++++++++++++++++++++++++++++-- src/shared/selinux-util.h | 5 + 4 files changed, 234 insertions(+), 6 deletions(-) diff --git a/src/shared/label-util.c b/src/shared/label-util.c index 2ffb43f88e..e5db8cda3f 100644 --- a/src/shared/label-util.c +++ b/src/shared/label-util.c @@ -6,6 +6,7 @@ #include "btrfs-util.h" #include "errno-util.h" #include "label-util.h" +#include "path-util.h" #include "selinux-util.h" #include "smack-util.h" @@ -97,6 +98,21 @@ int btrfs_subvol_make_label(const char *path, LabelContext *label_context) { return mac_smack_fix(path, 0); } +int mac_label_context_new(const char *root, LabelContext **ret) { + assert(ret); + + if (empty_or_root(root)) { + *ret = NULL; + return 0; + } + + return mac_selinux_label_context_new(root, ret); +} + +LabelContext* mac_label_context_free(LabelContext *c) { + return mac_selinux_label_context_free(c); +} + static int init_internal(bool lazy) { int r; diff --git a/src/shared/label-util.h b/src/shared/label-util.h index ea8c2b7165..5a810df8e5 100644 --- a/src/shared/label-util.h +++ b/src/shared/label-util.h @@ -27,3 +27,7 @@ int btrfs_subvol_make_label(const char *path, LabelContext *label_context); int mac_init(void); int mac_init_lazy(void); + +int mac_label_context_new(const char *root, LabelContext **ret); +LabelContext* mac_label_context_free(LabelContext *c); +DEFINE_TRIVIAL_CLEANUP_FUNC(LabelContext*, mac_label_context_free); diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index f275db1c81..7f959c2535 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -19,17 +19,22 @@ #include "alloc-util.h" #include "fd-util.h" -#include "path-util.h" #include "string-util.h" +#include "strv.h" #include "time-util.h" #endif +#include "chase.h" +#include "env-file.h" #include "errno-util.h" #include "label-util.h" +#include "path-util.h" #include "selinux-util.h" +#include "smack-util.h" #if HAVE_SELINUX DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(context_t, sym_context_free, context_freep, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(struct selabel_handle *, sym_selabel_close, selabel_closep, NULL); typedef enum Initialized { UNINITIALIZED, @@ -43,6 +48,20 @@ static int last_policyload = 0; static struct selabel_handle *label_hnd = NULL; static bool have_status_page = false; +struct LabelContext { + struct selabel_handle *label_hnd; + int rfd; + char *root; +}; + +static void selinux_policy_root_reset_and_freep(char **s) { + assert(s); + if (!*s) + return; + (void) sym_selinux_set_policy_root(*s); + *s = mfree(*s); +} + static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode, LabelContext *label_context) { return mac_selinux_create_file_prepare_at(dir_fd, path, mode, label_context); } @@ -52,6 +71,11 @@ static int mac_selinux_label_post(int dir_fd, const char *path, bool created, La return 0; } +static const LabelOps selinux_label_ops = { + .pre = mac_selinux_label_pre, + .post = mac_selinux_label_post, +}; + DLSYM_PROTOTYPE(avc_open) = NULL; DLSYM_PROTOTYPE(context_free) = NULL; DLSYM_PROTOTYPE(context_new) = NULL; @@ -75,7 +99,9 @@ DLSYM_PROTOTYPE(selinux_check_access) = NULL; DLSYM_PROTOTYPE(selinux_getenforcemode) = NULL; DLSYM_PROTOTYPE(selinux_init_load_policy) = NULL; DLSYM_PROTOTYPE(selinux_path) = NULL; +DLSYM_PROTOTYPE(selinux_policy_root) = NULL; DLSYM_PROTOTYPE(selinux_set_callback) = NULL; +DLSYM_PROTOTYPE(selinux_set_policy_root) = NULL; DLSYM_PROTOTYPE(selinux_status_close) = NULL; DLSYM_PROTOTYPE(selinux_status_getenforce) = NULL; DLSYM_PROTOTYPE(selinux_status_open) = NULL; @@ -121,7 +147,9 @@ int dlopen_libselinux(int log_level) { DLSYM_ARG(selinux_getenforcemode), DLSYM_ARG(selinux_init_load_policy), DLSYM_ARG(selinux_path), + DLSYM_ARG(selinux_policy_root), DLSYM_ARG(selinux_set_callback), + DLSYM_ARG(selinux_set_policy_root), DLSYM_ARG(selinux_status_close), DLSYM_ARG(selinux_status_getenforce), DLSYM_ARG(selinux_status_open), @@ -220,10 +248,6 @@ static int open_label_db(void) { static int selinux_init(bool force) { #if HAVE_SELINUX - static const LabelOps label_ops = { - .pre = mac_selinux_label_pre, - .post = mac_selinux_label_post, - }; int r; if (!mac_selinux_use()) @@ -256,7 +280,7 @@ static int selinux_init(bool force) { return r; } - r = label_ops_set(&label_ops); + r = label_ops_set(&selinux_label_ops); if (r < 0) return r; @@ -872,3 +896,182 @@ skipped: #endif return RET_NERRNO(bind(fd, addr, addrlen)); } + +#if HAVE_SELINUX +static int get_selinux_policy_root(int rfd, const char *root, char **ret) { + _cleanup_free_ char *policytype = NULL; + int r; + + assert(rfd >= 0); + assert(root); + assert(ret); + + /* Read the SELinux config from the alternate root, trying /etc and /usr/lib */ + FOREACH_STRING(config_dir, "/etc/selinux/config", "/usr/lib/selinux/config") { + _cleanup_close_ int fd = -EBADF; + + r = chaseat(rfd, rfd, config_dir, CHASE_MUST_BE_REGULAR, /* ret_path= */ NULL, &fd); + if (IN_SET(r, -ENOENT, -ENOTDIR, -EISDIR)) + continue; + if (r < 0) + return log_debug_errno(r, "Failed to resolve SELinux config path in root '%s': %m", root); + + r = parse_env_file_fd(fd, config_dir, "SELINUXTYPE", &policytype); + if (r == -ENOENT) + continue; + if (r < 0) + return log_debug_errno(r, "Failed to parse SELinux config '%s' in root '%s': %m", config_dir, root); + + if (!isempty(policytype)) + break; + } + + if (isempty(policytype)) { + log_debug("No SELINUXTYPE configured in alternate root '%s', skipping label context setup.", root); + *ret = NULL; + return 0; + } + + if (!filename_is_valid(policytype)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "SELINUXTYPE '%s' in alternate root '%s' is not a valid filename.", policytype, root); + + /* Look for the policy database under the alternate root */ + FOREACH_STRING(policy_dir, "/etc/selinux", "/usr/share/selinux") { + _cleanup_free_ char *p = NULL, *policy_subdir = NULL; + + policy_subdir = path_join(policy_dir, policytype); + if (!policy_subdir) + return log_oom(); + + r = chaseat(rfd, rfd, policy_subdir, CHASE_MUST_BE_DIRECTORY, &p, /* ret_fd= */ NULL); + if (IN_SET(r, -ENOENT, -ENOTDIR)) + continue; + if (r < 0) { + log_debug_errno(r, "Failed to resolve policy directory '%s' in root '%s': %m", policy_subdir, root); + continue; + } + + /* Validate that the file_contexts file resolves within the root, since libselinux + * will open it with plain fopen() which follows symlinks without confinement */ + _cleanup_free_ char *fc_subpath = NULL; + fc_subpath = path_join(policy_subdir, "contexts/files/file_contexts"); + if (!fc_subpath) + return log_oom(); + + r = chaseat(rfd, rfd, fc_subpath, CHASE_MUST_BE_REGULAR, /* ret_path= */ NULL, /* ret_fd= */ NULL); + if (IN_SET(r, -ENOENT, -ENOTDIR)) { + log_debug_errno(r, "file_contexts not found at '%s' in root '%s', skipping.", fc_subpath, root); + continue; + } + if (r < 0) { + log_debug_errno(r, "Failed to resolve file_contexts '%s' in root '%s': %m", fc_subpath, root); + continue; + } + + r = chaseat_prefix_root(p, root, ret); + if (r < 0) + return r; + + return 1; + } + + log_debug("SELinux policy directory for type '%s' not found in alternate root '%s', skipping.", policytype, root); + *ret = NULL; + return 0; +} +#endif + +int mac_selinux_label_context_new(const char *root, LabelContext **ret) { + assert(root); + assert(!empty_or_root(root)); + assert(ret); + +#if HAVE_SELINUX + _cleanup_free_ char *policyroot = NULL, *canonical_root = NULL; + _cleanup_close_ int rfd = -EBADF; + int r; + + if (mac_smack_use()) { + *ret = NULL; + return 0; + } + + r = dlopen_libselinux(LOG_ERR); + if (r < 0) + return r; + + mac_selinux_disable_logging(); + + r = chaseat(AT_FDCWD, AT_FDCWD, root, CHASE_MUST_BE_DIRECTORY, &canonical_root, &rfd); + if (r < 0) + return log_debug_errno(r, "Failed to open root directory '%s': %m", root); + + r = get_selinux_policy_root(rfd, root, &policyroot); + if (r < 0) + return r; + if (r == 0) { + *ret = NULL; + return 0; + } + + /* Temporarily switch the policy root so selabel_open() reads the image's file_contexts. + * The handle bakes in the database at open time, so we can reset the root immediately after. + * We must strdup the saved root because selinux_set_policy_root() frees the internal buffer. */ + _cleanup_(selinux_policy_root_reset_and_freep) char *saved_policy_root = NULL; + const char *p = sym_selinux_policy_root(); + if (p) { + saved_policy_root = strdup(p); + if (!saved_policy_root) + return log_oom(); + } + + r = RET_NERRNO(sym_selinux_set_policy_root(policyroot)); + if (r < 0) + return log_debug_errno(r, "Failed to set SELinux policy root to '%s': %m", policyroot); + + _cleanup_(selabel_closep) struct selabel_handle *hnd = sym_selabel_open(SELABEL_CTX_FILE, /* opts= */ NULL, /* nopts= */ 0); + int saved_errno = errno; + + /* Reset immediately - the handle baked in the database at open time */ + selinux_policy_root_reset_and_freep(&saved_policy_root); + + if (!hnd) + return log_debug_errno(saved_errno, "Failed to open SELinux label database for alternate root '%s': %m", root); + + r = label_ops_set(&selinux_label_ops); + if (r < 0 && r != -EBUSY) + return r; + + _cleanup_free_ LabelContext *c = new(LabelContext, 1); + if (!c) + return log_oom(); + + *c = (LabelContext) { + .label_hnd = TAKE_PTR(hnd), + .rfd = TAKE_FD(rfd), + .root = TAKE_PTR(canonical_root), + }; + + *ret = TAKE_PTR(c); + return 0; +#else + *ret = NULL; + return 0; +#endif +} + +LabelContext* mac_selinux_label_context_free(LabelContext *c) { + if (!c) + return NULL; + +#if HAVE_SELINUX + if (c->label_hnd) + sym_selabel_close(c->label_hnd); + + safe_close(c->rfd); + free(c->root); +#endif + + return mfree(c); +} diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h index 06bae27446..3f2e4dc77b 100644 --- a/src/shared/selinux-util.h +++ b/src/shared/selinux-util.h @@ -41,7 +41,9 @@ extern DLSYM_PROTOTYPE(selinux_check_access); extern DLSYM_PROTOTYPE(selinux_getenforcemode); extern DLSYM_PROTOTYPE(selinux_init_load_policy); extern DLSYM_PROTOTYPE(selinux_path); +extern DLSYM_PROTOTYPE(selinux_policy_root); extern DLSYM_PROTOTYPE(selinux_set_callback); +extern DLSYM_PROTOTYPE(selinux_set_policy_root); extern DLSYM_PROTOTYPE(selinux_status_close); extern DLSYM_PROTOTYPE(selinux_status_getenforce); extern DLSYM_PROTOTYPE(selinux_status_open); @@ -114,3 +116,6 @@ int mac_selinux_create_socket_prepare(const char *label); void mac_selinux_create_socket_clear(void); int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); + +int mac_selinux_label_context_new(const char *root, LabelContext **ret); +LabelContext* mac_selinux_label_context_free(LabelContext *c); From f4f6a56db4b41f3a1e94fc2b1d18f662e10ca5e2 Mon Sep 17 00:00:00 2001 From: Simon de Vlieger Date: Sat, 4 Jul 2026 12:44:53 +0200 Subject: [PATCH 3/4] selinux: use LabelContext in label callbacks With the plumbing and context type in place, make the SELinux pre/post callbacks use the alternate context when label_context is non-NULL, so files get labeled according to the target image's policy rather than the host's. Errors from the host kernel not recognising image-specific contexts (EINVAL from setfscreatecon_raw) are logged at debug level and skipped gracefully, since this is expected when the image carries labels the host policy doesn't define. Signed-off-by: Simon de Vlieger --- src/shared/selinux-util.c | 130 ++++++++++++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 13 deletions(-) diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index 7f959c2535..61bd8ba7b9 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -67,7 +67,11 @@ static int mac_selinux_label_pre(int dir_fd, const char *path, mode_t mode, Labe } static int mac_selinux_label_post(int dir_fd, const char *path, bool created, LabelContext *label_context) { - mac_selinux_create_file_clear(); + if (label_context) { + PROTECT_ERRNO; + (void) sym_setfscreatecon_raw(NULL); + } else + mac_selinux_create_file_clear(); return 0; } @@ -396,12 +400,32 @@ static int setfilecon_idempotent(int fd, const char *context) { return RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), context)); } +static const char* strip_root_path(const char *path, const char *root) { + assert(path); + assert(root); + + const char *suffix = path_startswith(path, root); + if (!suffix) + return NULL; + + if (isempty(suffix)) + return "/"; + + assert(suffix > path); + assert(suffix[-1] == '/'); + + return suffix - 1; /* back up to include the leading / */ +} + static int selinux_fix_fd( int fd, const char *label_path, - LabelFixFlags flags) { + LabelFixFlags flags, + LabelContext *c) { _cleanup_freecon_ char* fcon = NULL; + struct selabel_handle *hnd; + const char *lookup_path; struct stat st; int r; @@ -412,16 +436,30 @@ static int selinux_fix_fd( if (fstat(fd, &st) < 0) return -errno; - /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ - mac_selinux_maybe_reload(); - if (!label_hnd) - return 0; + if (c) { + hnd = c->label_hnd; - if (sym_selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) { + lookup_path = strip_root_path(label_path, c->root); + if (!lookup_path) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Path '%s' is not under root '%s', refusing SELinux label fix.", label_path, c->root); + } else { + /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ + mac_selinux_maybe_reload(); + if (!label_hnd) + return 0; + hnd = label_hnd; + lookup_path = label_path; + } + + if (sym_selabel_lookup_raw(hnd, &fcon, lookup_path, st.st_mode) < 0) { /* If there's no label to set, then exit without warning */ if (errno == ENOENT) return 0; + if (c) + return log_debug_errno(errno, "Unable to look up intended SELinux security context of %s (looked up as %s): %m", label_path, lookup_path); + return log_selinux_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path); } @@ -437,6 +475,16 @@ static int selinux_fix_fd( if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; + if (c) { + /* EINVAL means the host kernel doesn't know this context, degrade gracefully */ + if (r == -EINVAL) { + log_debug_errno(r, "Unable to fix SELinux security context of %s, ignoring: %m", label_path); + return 0; + } + + return log_debug_errno(r, "Unable to fix SELinux security context of %s: %m", label_path); + } + return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path); } #endif @@ -456,12 +504,19 @@ int mac_selinux_fix_full( _cleanup_free_ char *p = NULL; int inode_fd, r; - r = selinux_init(/* force= */ false); - if (r <= 0) - return r; + LabelContext *c = label_context; - if (!label_hnd) - return 0; + if (c) { + if (!c->label_hnd) + return 0; + } else { + r = selinux_init(/* force= */ false); + if (r <= 0) + return r; + + if (!label_hnd) + return 0; + } if (inode_path) { opened_fd = openat(atfd, inode_path, O_NOFOLLOW|O_CLOEXEC|O_PATH); @@ -488,7 +543,7 @@ int mac_selinux_fix_full( } } - return selinux_fix_fd(inode_fd, label_path, flags); + return selinux_fix_fd(inode_fd, label_path, flags, c); #else return 0; #endif @@ -714,6 +769,52 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) return 0; } + +static int selinux_create_file_prepare_context(int dir_fd, const char *path, mode_t mode, LabelContext *c) { + _cleanup_free_ char *abspath = NULL; + _cleanup_freecon_ char *filecon = NULL; + const char *lookup_path; + int r; + + assert(c); + assert(c->label_hnd); + + /* Resolve the path to absolute if needed */ + if (isempty(path) || !path_is_absolute(path)) { + r = fd_get_path(dir_fd, &abspath); + if (r < 0) + return r; + + if (!isempty(path) && !path_extend(&abspath, path)) + return -ENOMEM; + + path = abspath; + } + + /* Strip the root prefix so we look up the path as it would appear inside the image */ + lookup_path = strip_root_path(path, c->root); + if (!lookup_path) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Path '%s' is not under root '%s', refusing SELinux labeling.", path, c->root); + + r = RET_NERRNO(sym_selabel_lookup_raw(c->label_hnd, &filecon, lookup_path, mode)); + if (r == -ENOENT) + return 0; + if (r < 0) + return log_debug_errno(r, "Failed to determine SELinux security context for %s (looked up as %s): %m", path, lookup_path); + + if (sym_setfscreatecon_raw(filecon) < 0) { + /* EINVAL means the host kernel doesn't know this context, degrade gracefully */ + if (errno == EINVAL) { + log_debug_errno(errno, "Failed to set SELinux security context %s for %s, ignoring: %m", filecon, path); + return 0; + } + + return log_debug_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path); + } + + return 0; +} #endif int mac_selinux_create_file_prepare_at( @@ -728,6 +829,9 @@ int mac_selinux_create_file_prepare_at( assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + if (label_context) + return selinux_create_file_prepare_context(dir_fd, path, mode, label_context); + r = selinux_init(/* force= */ false); if (r <= 0) return r; From d652f6dc44bc960bb3583987a186d72a92e67d23 Mon Sep 17 00:00:00 2001 From: Simon de Vlieger Date: Sat, 4 Jul 2026 13:10:21 +0200 Subject: [PATCH 4/4] selinux: wire up LabelContext in tmpfiles, firstboot, sysusers 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 --- src/firstboot/firstboot.c | 39 +++++++++++++++++++++++++-------------- src/sysusers/sysusers.c | 31 ++++++++++++++++++++----------- src/tmpfiles/tmpfiles.c | 36 +++++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index ed6817a186..a76b4c755e 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -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); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 9c52bce66b..56f3dc3953 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -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(); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 756c1458e3..d1d7c42ffa 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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)