From: Simon de Vlieger Date: Sat, 4 Jul 2026 10:44:53 +0000 (+0200) Subject: selinux: use LabelContext in label callbacks X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f4f6a56db4b41f3a1e94fc2b1d18f662e10ca5e2;p=thirdparty%2Fsystemd.git 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 --- diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index 7f959c25355..61bd8ba7b9c 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;