On Fri, 5 Jan 2024 at 20:15, James Carter <jwcart2@xxxxxxxxx> wrote: > > On Wed, Dec 13, 2023 at 11:14 AM Christian Göttsche > <cgzones@xxxxxxxxxxxxxx> wrote: > > > > The common SELinux practice is to have a distinct label for terminals in > > use by logged in users. This allows to differentiate access on the > > associated terminal (e.g. user_tty_device_t) vs foreign ones (e.g. > > tty_device_t or sysadm_tty_device_t). Therefore the application > > performing the user login and setting up the associated terminal should > > label that terminal according to the loaded SELinux policy. Commonly > > this is done by pam_selinux(7). Since sulogin(8) does not use pam(7) > > perform the necessary steps manually. > > > > Fixes: https://github.com/util-linux/util-linux/issues/1578 > > > > Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> > > The SELinux parts look ok to me. > Reviewed-by: James Carter <jwcart2@xxxxxxxxx> Thanks for the review Jim. Applied via https://github.com/util-linux/util-linux/commit/eb02db62685cca30e5afc61652c8b6e9cd0774e9 > > > --- > > Upstream pull-request: https://github.com/util-linux/util-linux/pull/2650 > > --- > > login-utils/sulogin-consoles.c | 4 + > > login-utils/sulogin-consoles.h | 4 + > > login-utils/sulogin.c | 156 +++++++++++++++++++++++++++++---- > > 3 files changed, 146 insertions(+), 18 deletions(-) > > > > diff --git a/login-utils/sulogin-consoles.c b/login-utils/sulogin-consoles.c > > index 9ae525556..0dca949f4 100644 > > --- a/login-utils/sulogin-consoles.c > > +++ b/login-utils/sulogin-consoles.c > > @@ -341,6 +341,10 @@ int append_console(struct list_head *consoles, const char * const name) > > tail->id = last ? last->id + 1 : 0; > > tail->pid = -1; > > memset(&tail->tio, 0, sizeof(tail->tio)); > > +#ifdef HAVE_LIBSELINUX > > + tail->reset_tty_context = NULL; > > + tail->user_tty_context = NULL; > > +#endif > > > > return 0; > > } > > diff --git a/login-utils/sulogin-consoles.h b/login-utils/sulogin-consoles.h > > index 12032c997..608c4f84f 100644 > > --- a/login-utils/sulogin-consoles.h > > +++ b/login-utils/sulogin-consoles.h > > @@ -44,6 +44,10 @@ struct console { > > pid_t pid; > > struct chardata cp; > > struct termios tio; > > +#ifdef HAVE_LIBSELINUX > > + char *reset_tty_context; > > + char *user_tty_context; > > +#endif > > }; > > > > extern int detect_consoles(const char *device, int fallback, > > diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c > > index 019f35092..2682c30fb 100644 > > --- a/login-utils/sulogin.c > > +++ b/login-utils/sulogin.c > > @@ -99,6 +99,81 @@ static int locked_account_password(const char * const passwd) > > return 0; > > } > > > > +#ifdef HAVE_LIBSELINUX > > +/* > > + * Cached check whether SELinux is enabled. > > + */ > > +static int is_selinux_enabled_cached(void) > > +{ > > + static int cache = -1; > > + > > + if (cache == -1) > > + cache = is_selinux_enabled(); > > + > > + return cache; > > +} > > + > > +/* Computed SELinux login context. */ > > +static char *login_context; > > + > > +/* > > + * Compute SELinux login context. > > + */ > > +static void compute_login_context(void) > > +{ > > + char *seuser = NULL; > > + char *level = NULL; > > + > > + if (is_selinux_enabled_cached() == 0) > > + goto cleanup; > > + > > + if (getseuserbyname("root", &seuser, &level) == -1) { > > + warnx(_("failed to compute seuser")); > > + goto cleanup; > > + } > > + > > + if (get_default_context_with_level(seuser, level, NULL, &login_context) == -1) { > > + warnx(_("failed to compute default context")); > > + goto cleanup; > > + } > > + > > +cleanup: > > + free(seuser); > > + free(level); > > +} > > + > > +/* > > + * Compute SELinux terminal context. > > + */ > > +static void tcinit_selinux(struct console *con) > > +{ > > + security_class_t tclass; > > + > > + if (!login_context) > > + return; > > + > > + if (fgetfilecon(con->fd, &con->reset_tty_context) == -1) { > > + warn(_("failed to get context of terminal %s"), con->tty); > > + return; > > + } > > + > > + tclass = string_to_security_class("chr_file"); > > + if (tclass == 0) { > > + warnx(_("security class chr_file not available")); > > + freecon(con->reset_tty_context); > > + con->reset_tty_context = NULL; > > + return; > > + } > > + > > + if (security_compute_relabel(login_context, con->reset_tty_context, tclass, &con->user_tty_context) == -1) { > > + warnx(_("failed to compute relabel context of terminal")); > > + freecon(con->reset_tty_context); > > + con->reset_tty_context = NULL; > > + return; > > + } > > +} > > +#endif > > + > > /* > > * Fix the tty modes and set reasonable defaults. > > */ > > @@ -132,6 +207,10 @@ static void tcinit(struct console *con) > > errno = 0; > > #endif > > > > +#ifdef HAVE_LIBSELINUX > > + tcinit_selinux(con); > > +#endif > > + > > #ifdef TIOCGSERIAL > > if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0) > > con->flags |= CON_SERIAL; > > @@ -785,7 +864,7 @@ out: > > /* > > * Password was OK, execute a shell. > > */ > > -static void sushell(struct passwd *pwd) > > +static void sushell(struct passwd *pwd, struct console *con) > > { > > char shell[PATH_MAX]; > > char home[PATH_MAX]; > > @@ -842,22 +921,21 @@ static void sushell(struct passwd *pwd) > > mask_signal(SIGHUP, SIG_DFL, NULL); > > > > #ifdef HAVE_LIBSELINUX > > - if (is_selinux_enabled() > 0) { > > - char *scon = NULL; > > - char *seuser = NULL; > > - char *level = NULL; > > - > > - if (getseuserbyname("root", &seuser, &level) == 0) { > > - if (get_default_context_with_level(seuser, level, 0, &scon) == 0) { > > - if (setexeccon(scon) != 0) > > - warnx(_("setexeccon failed")); > > - freecon(scon); > > - } > > + if (is_selinux_enabled_cached() == 1) { > > + if (con->user_tty_context) { > > + if (fsetfilecon(con->fd, con->user_tty_context) == -1) > > + warn(_("failed to set context to %s for terminal %s"), con->user_tty_context, con->tty); > > + } > > + > > + if (login_context) { > > + if (setexeccon(login_context) == -1) > > + warn(_("failed to set exec context to %s"), login_context); > > } > > - free(seuser); > > - free(level); > > } > > +#else > > + (void)con; > > #endif > > + > > execl(su_shell, shell, (char *)NULL); > > warn(_("failed to execute %s"), su_shell); > > > > @@ -866,6 +944,30 @@ static void sushell(struct passwd *pwd) > > warn(_("failed to execute %s"), "/bin/sh"); > > } > > > > +#ifdef HAVE_LIBSELINUX > > +static void tcreset_selinux(struct list_head *consoles) { > > + struct list_head *ptr; > > + struct console *con; > > + > > + if (is_selinux_enabled_cached() == 0) > > + return; > > + > > + list_for_each(ptr, consoles) { > > + con = list_entry(ptr, struct console, entry); > > + > > + if (con->fd < 0) > > + continue; > > + if (!con->reset_tty_context) > > + continue; > > + if (fsetfilecon(con->fd, con->reset_tty_context) == -1) > > + warn(_("failed to reset context to %s for terminal %s"), con->reset_tty_context, con->tty); > > + > > + freecon(con->reset_tty_context); > > + con->reset_tty_context = NULL; > > + } > > +} > > +#endif > > + > > static void usage(void) > > { > > FILE *out = stdout; > > @@ -1015,6 +1117,10 @@ int main(int argc, char **argv) > > return EXIT_FAILURE; > > } > > > > +#ifdef HAVE_LIBSELINUX > > + compute_login_context(); > > +#endif > > + > > /* > > * Ask for the password on the consoles. > > */ > > @@ -1034,9 +1140,18 @@ int main(int argc, char **argv) > > } > > ptr = (&consoles)->next; > > > > - if (ptr->next == &consoles) { > > - con = list_entry(ptr, struct console, entry); > > - goto nofork; > > +#ifdef HAVE_LIBSELINUX > > + /* > > + * Always fork with SELinux enabled, so the parent can restore the > > + * terminal context afterwards. > > + */ > > + if (is_selinux_enabled_cached() == 0) > > +#endif > > + { > > + if (ptr->next == &consoles) { > > + con = list_entry(ptr, struct console, entry); > > + goto nofork; > > + } > > } > > > > > > @@ -1087,7 +1202,7 @@ int main(int argc, char **argv) > > #endif > > if (doshell) { > > /* sushell() unmask signals */ > > - sushell(pwd); > > + sushell(pwd, con); > > > > mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit); > > mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp); > > @@ -1193,5 +1308,10 @@ int main(int argc, char **argv) > > } while (1); > > > > mask_signal(SIGCHLD, SIG_DFL, NULL); > > + > > +#ifdef HAVE_LIBSELINUX > > + tcreset_selinux(&consoles); > > +#endif > > + > > return EXIT_SUCCESS; > > } > > -- > > 2.43.0 > > > >