$ cat 0001-selinux-use-the-labeldb-for-a-manual-transition-when.patch From e99be9903c9a54f045f5006146348e4cabaae281 Mon Sep 17 00:00:00 2001 From: Rahul Sandhu Date: Mon, 2 Jun 2025 17:35:03 +0100 Subject: [PATCH] selinux: use the labeldb for a manual transition when creating dirs Signed-off-by: Rahul Sandhu --- meson.build | 9 +++- meson_options.txt | 5 ++ src/fs_utils.cc | 128 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 770b982..a0d349f 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,12 @@ scdoc_dep = dependency( native: true ) +libselinux_dep = dependency( + 'libselinux', + version: '>=2.1.9', + required: get_option('support_selinux') +) + have_dinit = get_option('dinit').enabled() have_runit = get_option('runit').enabled() @@ -31,6 +37,7 @@ conf_data.set_quoted('CONF_PATH', join_paths( get_option('prefix'), get_option('sysconfdir'), 'turnstile' )) conf_data.set10('MANAGE_RUNDIR', get_option('manage_rundir')) +conf_data.set10('HAVE_SELINUX', libselinux_dep.found()) conf_data.set('HAVE_PAM_MISC', pam_misc_dep.found()) @@ -82,7 +89,7 @@ daemon = executable( 'turnstiled', daemon_sources, include_directories: extra_inc, install: true, - dependencies: [rt_dep, pam_dep, pam_misc_dep], + dependencies: [rt_dep, pam_dep, pam_misc_dep, libselinux_dep], gnu_symbol_visibility: 'hidden' ) diff --git a/meson_options.txt b/meson_options.txt index 29abb69..4d3af0c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -38,6 +38,11 @@ option('manage_rundir', description: 'Whether to manage rundir by default' ) +option('support_selinux', + type: 'feature', value: 'auto', + description: 'Whether to support SELinux', +) + option('man', type: 'boolean', value: true, description: 'Whether to generate manpages' diff --git a/src/fs_utils.cc b/src/fs_utils.cc index ac91921..6ae8d0f 100644 --- a/src/fs_utils.cc +++ b/src/fs_utils.cc @@ -10,11 +10,59 @@ #include "turnstiled.hh" +#ifdef HAVE_SELINUX +#include +#include +#endif + int dir_make_at(int dfd, char const *dname, mode_t mode) { int sdfd = openat(dfd, dname, O_RDONLY | O_NOFOLLOW); struct stat st; int reterr = 0; int omask = umask(0); + +#ifdef HAVE_SELINUX + // We can't rely on policy transitions to set the user field of the context + // correctly as that depends on the seuser db, so calculate the context to + // create the runtimedir with ourselves. + char *path = nullptr; + char *context = nullptr; + { + char procfd[64]; + ssize_t len; + snprintf(procfd, sizeof(procfd), "/proc/self/fd/%d", dfd); + char dfd_path[PATH_MAX]; + len = readlink(procfd, dfd_path, sizeof(dfd_path)-1); + if (len < 0) { + goto ret_err; + } + dfd_path[len] = '\0'; + path = (char *)malloc(strlen(dfd_path) + 1 + strlen(dname) + 2); + if (!path) { + goto ret_err; + } + sprintf(path, "%s/%s", dfd_path, dname); + + struct selabel_handle *sehandle = + selabel_open(SELABEL_CTX_FILE, nullptr, 0); + if (!sehandle) { + perror("selabel_open"); + goto ret_err; + } + if (selabel_lookup_raw(sehandle, &context, path, mode) < 0) { + perror("selabel_lookup_raw"); + selabel_close(sehandle); + goto ret_err; + } + selabel_close(sehandle); + if (setfscreatecon_raw(context) < 0) { + perror("setfscreatecon_raw"); + goto ret_err; + } + } + print_err ("selinux: %s | %s", path, context); +#endif + if (fstat(sdfd, &st) || !S_ISDIR(st.st_mode)) { close(sdfd); if (mkdirat(dfd, dname, mode)) { @@ -29,6 +77,7 @@ int dir_make_at(int dfd, char const *dname, mode_t mode) { goto ret_err; } } else { + // TODO: dir already exists, call lsetfilecon. /* dir_clear_contents closes the descriptor, we need to keep it */ int nfd; if ((fchmod(sdfd, mode) < 0) || ((nfd = dup(sdfd)) < 0)) { @@ -39,9 +88,34 @@ int dir_make_at(int dfd, char const *dname, mode_t mode) { goto ret_err; } } + +#ifdef HAVE_SELINUX + // Reset fs creation context so new objects are labelled correctly. + if (setfscreatecon(nullptr) < 0) { + perror("setfscreatecon"); + goto ret_err; + } + if (context) { + free(context); + } + if (path) { + free(path); + } +#endif + umask(omask); return sdfd; + ret_err: +#ifdef HAVE_SELINUX + setfscreatecon(nullptr); + if (context) { + free(context); + } + if (path) { + free(path); + } +#endif umask(omask); if (sdfd >= 0) { close(sdfd); @@ -97,6 +171,46 @@ bool rundir_make(char *rundir, unsigned int uid, unsigned int gid) { sl = std::strchr(dirbase, '/'); } umask(omask); + +#ifdef HAVE_SELINUX + // We can't rely on policy transitions to set the user field of the context + // correctly as that depends on the seuser db, so calculate the context to + // create the runtimedir with ourselves. + char *context = nullptr; + { + struct selabel_handle *sehandle = + selabel_open(SELABEL_CTX_FILE, nullptr, 0); + if (!sehandle) { + print_err( + "rundir: failed to make rundir %s (%s)", + rundir, strerror(errno) + ); + close(bfd); + return false; + } + if (selabel_lookup_raw(sehandle, &context, rundir, 0700) < 0) { + print_err( + "rundir: failed to make rundir %s (%s)", + rundir, strerror(errno) + ); + selabel_close(sehandle); + close(bfd); + return false; + } + selabel_close(sehandle); + if (setfscreatecon_raw(context) < 0) { + print_err( + "rundir: failed to make rundir %s (%s)", + rundir, strerror(errno) + ); + close(bfd); + return false; + } + } + print_err ("selinux: %s | %s", rundir, context); +#endif + + // TODO: lsetfilecon for dir already existing. /* now create rundir or at least sanitize its perms */ if ( (fstatat(bfd, dirbase, &dstat, AT_SYMLINK_NOFOLLOW) < 0) || @@ -115,6 +229,20 @@ bool rundir_make(char *rundir, unsigned int uid, unsigned int gid) { close(bfd); return false; } + +#ifdef HAVE_SELINUX + // Reset fs creation context so new objects are labelled correctly. + if (setfscreatecon(nullptr) < 0) { + perror("setfscreatecon"); + close(bfd); + free(context); + return false; + } + if (context) { + free(context); + } +#endif + if (fchownat(bfd, dirbase, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) { print_err("rundir: fchownat failed for rundir (%s)", strerror(errno)); close(bfd); -- 2.49.0 $ cat 0001-turnstiled-use-labeldb-when-creating-user-owned-fifo.patch From d809f35f6c0dbd0f30559eafaaa614d484f7b230 Mon Sep 17 00:00:00 2001 From: Rahul Sandhu Date: Tue, 3 Jun 2025 18:10:25 +0100 Subject: [PATCH] turnstiled: use labeldb when creating user-owned fifofile Signed-off-by: Rahul Sandhu --- src/turnstiled.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/turnstiled.cc b/src/turnstiled.cc index cf9e6d3..cf8580f 100644 --- a/src/turnstiled.cc +++ b/src/turnstiled.cc @@ -33,6 +33,11 @@ #include "turnstiled.hh" #include "utils.hh" +#ifdef HAVE_SELINUX +#include +#include +#endif + #ifndef CONF_PATH #error "No CONF_PATH is defined" #endif @@ -159,10 +164,57 @@ static bool srv_start(login &lgn) { } print_dbg("srv: create readiness pipe"); unlinkat(lgn.dirfd, "ready", 0); +#ifdef HAVE_SELINUX + // We can't rely on policy transitions to set the user field of the context + // correctly as that depends on the seuser db, so calculate the context to + // create the runtimedir with ourselves. + char *context = nullptr; + { + struct selabel_handle *sehandle = + selabel_open(SELABEL_CTX_FILE, nullptr, 0); + if (!sehandle) { + print_err("srv: failed to make ready pipe (%s)", strerror(errno)); + return false; + } + char ready_path[PATH_MAX]; + if (const int r = std::snprintf(ready_path, sizeof(ready_path), + "%s/%s/%u/ready", RUN_PATH, SOCK_DIR, lgn.uid); + r < 0 || r >= PATH_MAX) { + print_err("srv: failed to make ready pipe (%s)", strerror(errno)); + selabel_close(sehandle); + return false; + } + if (selabel_lookup_raw(sehandle, &context, ready_path, 0700) < 0) { + print_err("srv: failed to make ready pipe (%s)", strerror(errno)); + selabel_close(sehandle); + return false; + } + selabel_close(sehandle); + if (setfscreatecon_raw(context) < 0) { + print_err("srv: failed to make ready pipe (%s)", strerror(errno)); + free(context); + return false; + } + } +#endif if (mkfifoat(lgn.dirfd, "ready", 0700) < 0) { print_err("srv: failed to make ready pipe (%s)", strerror(errno)); return false; } +#ifdef HAVE_SELINUX + // Reset fs creation context so new objects are labelled correctly. + if (context) { + free(context); + } + if (setfscreatecon(nullptr) < 0) { + print_err( + "srv: failed to set up ready pipe (%s)", strerror(errno) + ); + unlinkat(lgn.dirfd, "ready", 0); + lgn.remove_sdir(); + return false; + } +#endif /* ensure it's owned by user too, and open in nonblocking mode */ if (fchownat( lgn.dirfd, "ready", lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW -- 2.49.0