From: Serge Hallyn Date: Tue, 9 Jun 2026 01:08:04 +0000 (-0500) Subject: Avoid falling prey to tiocsti X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f384b3dfcba36b784ac74e37918b8d47f6d676ef;p=thirdparty%2Fshadow.git Avoid falling prey to tiocsti We've long known (see https://www.halfdog.net/Security/2012/TtyPushbackPrivilegeEscalation/ and https://jdebp.uk/FGA/dont-abuse-su-for-dropping-privileges.html) that su should be used to gain but not drop privilege. Much more recently, linux added the ability to prevent TIOCSTI through a configurable /proc/sys/dev/tty/legacy_tiocsti setting. If /proc/sys/dev/tty/legacy_tiocsti is set to 0, then we are protected from the callee injecting commands on caller's tty through TIOCSTI. If it's 1, or doesn't exist, then we are not. That can be dangerous if caller is root. We currently give up the controlling terminal for non-interactive uses of su (-c). Let's do that for interactive calls as well, only in the dangerous case. --- diff --git a/src/su.c b/src/su.c index 8cea0d1f0..e4dc72098 100644 --- a/src/su.c +++ b/src/su.c @@ -56,6 +56,7 @@ #ifdef USE_PAM #include "pam_defs.h" #endif /* USE_PAM */ +#include "io/fgets/fgets.h" #include "pwauth.h" #include "prototypes.h" #include "shadowlog.h" @@ -996,6 +997,24 @@ static void set_environment (struct passwd *pw) } +// See linux.git 83efeeeb3d04 (2022-10-22; "tty: Allow TIOCSTI to be disabled") +static bool legacy_tiocsti_is_disabled(void) +{ + char buf[3]; + FILE *fp; + void *ret; + + fp = fopen("/proc/sys/dev/tty/legacy_tiocsti", "r"); + if (NULL == fp) + return false; + ret = fgets_a(buf, fp); + fclose(fp); + if (ret == NULL) + return false; + + return streq(buf, "0\n"); +} + /* * su - switch user id * @@ -1010,6 +1029,7 @@ int main (int argc, char **argv) { const char *cp; struct passwd *pw = NULL; + bool need_pty_prot; #ifdef USE_PAM int ret; @@ -1023,6 +1043,8 @@ int main (int argc, char **argv) save_caller_context(); + need_pty_prot = caller_is_root && !legacy_tiocsti_is_disabled(); + OPENLOG (Prog); process_flags (argc, argv); @@ -1152,7 +1174,7 @@ int main (int argc, char **argv) set_environment (pw); - if (!doshell) { + if (!doshell || need_pty_prot) { /* There is no need for a controlling terminal. * This avoids the callee to inject commands on * the caller's tty. */