Re: [UTIL-LINUX PATCH] sulogin: relabel terminal according to SELinux policy

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
> >
> >





[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux