From 23884bba3854ed35ebe19adbb2ad1ea2972dab79 Mon Sep 17 00:00:00 2001
From: Tobias Stoeckmann <tobias@stoeckmann.org>
Date: Thu, 21 Sep 2023 20:25:55 +0200
Subject: [PATCH] login: prevent undefined ioctl and tcsetattr calls

Do not call tcsetattr if tcgetattr fails, because the content of
tt and ttt is undefined in that case.

Also do not just warn if ioctl fails, but also avoid calling it again
after tty has been re-opened.

I've solved this by setting struct variables to values which cannot be
valid at this point. If they do have these exact values, then the
calls will be prevented.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
---
 login-utils/login.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/login-utils/login.c b/login-utils/login.c
index d6c6af7..8364497 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -176,9 +176,10 @@ static void __attribute__((__noreturn__))
 	struct termios ti;
 
 	/* reset echo */
-	tcgetattr(0, &ti);
-	ti.c_lflag |= ECHO;
-	tcsetattr(0, TCSANOW, &ti);
+	if (tcgetattr(0, &ti) >= 0) {
+		ti.c_lflag |= ECHO;
+		tcsetattr(0, TCSANOW, &ti);
+	}
 	_exit(EXIT_SUCCESS);	/* %% */
 }
 
@@ -512,8 +513,8 @@ static void chown_tty(struct login_context *cxt)
 static void init_tty(struct login_context *cxt)
 {
 	struct stat st;
-	struct termios tt, ttt;
-	struct winsize ws;
+	struct termios tt, ttt = { 0 };
+	struct winsize ws = { 0 };
 	int fd;
 
 	cxt->tty_mode = (mode_t) getlogindefs_num("TTYPERM", TTY_MODE);
@@ -548,13 +549,18 @@ static void init_tty(struct login_context *cxt)
 
 	/* The TTY size might be reset to 0x0 by the kernel when we close the stdin/stdout/stderr file
 	 * descriptors so let's save the size now so we can reapply it later */
-	memset(&ws, 0, sizeof(struct winsize));
-	if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+	if (ioctl(fd, TIOCGWINSZ, &ws) < 0) {
 		syslog(LOG_WARNING, _("TIOCGWINSZ ioctl failed: %m"));
+		ws.ws_row = 0;
+		ws.ws_col = 0;
+	}
 
-	tcgetattr(fd, &tt);
-	ttt = tt;
-	ttt.c_cflag &= ~HUPCL;
+	if (tcgetattr(fd, &tt) >= 0) {
+		ttt = tt;
+		ttt.c_cflag &= ~HUPCL;
+	} else {
+		ttt.c_cflag = HUPCL;
+	}
 
 	if ((fchown(fd, 0, 0) || fchmod(fd, cxt->tty_mode)) && errno != EROFS) {
 
@@ -564,7 +570,8 @@ static void init_tty(struct login_context *cxt)
 	}
 
 	/* Kill processes left on this tty */
-	tcsetattr(fd, TCSANOW, &ttt);
+	if ((ttt.c_cflag & HUPCL) == 0)
+		tcsetattr(fd, TCSANOW, &ttt);
 
 	/*
 	 * Let's close file descriptors before vhangup
@@ -582,7 +589,8 @@ static void init_tty(struct login_context *cxt)
 	open_tty(cxt->tty_path);
 
 	/* restore tty modes */
-	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
+	if ((ttt.c_cflag & HUPCL) == 0)
+		tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
 
 	/* Restore tty size */
 	if (ws.ws_row > 0 || ws.ws_col > 0)
-- 
2.33.0

