From 77fe6ae51e53e46ef3b2cf6c379c9893677876f0 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 22 May 2025 08:38:29 -0600 Subject: [PATCH] Use TCSAFLUSH not TCSADRAIN when disabling echo A long time ago this was changed from TCSAFLUSH to TCSADRAIN due to some systems having problems with TCSAFLUSH. That should no longer be a concern. Using TCSAFLUSH ensures that password input that has been received by the kernel, but not yet read by sudo, will be discarded and not echoed. --- include/sudo_util.h | 3 ++- lib/util/term.c | 13 ++++++++++--- lib/util/util.exp.in | 1 + src/tgetpass.c | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/sudo_util.h b/include/sudo_util.h index a50a966d8..2da62d65e 100644 --- a/include/sudo_util.h +++ b/include/sudo_util.h @@ -342,7 +342,8 @@ extern int (*sudo_printf)(int msg_type, const char * restrict fmt, ...); sudo_dso_public bool sudo_isatty_v1(int fd, struct stat *sbp); #define sudo_isatty(_a, _b) sudo_isatty_v1((_a), (_b)) sudo_dso_public bool sudo_term_cbreak_v1(int fd); -#define sudo_term_cbreak(_a) sudo_term_cbreak_v1((_a)) +sudo_dso_public bool sudo_term_cbreak_v2(int fd, bool flush); +#define sudo_term_cbreak(_a, _b) sudo_term_cbreak_v2((_a), (_b)) sudo_dso_public bool sudo_term_copy_v1(int src, int dst); #define sudo_term_copy(_a, _b) sudo_term_copy_v1((_a), (_b)) sudo_dso_public bool sudo_term_noecho_v1(int fd); diff --git a/lib/util/term.c b/lib/util/term.c index a74e9d022..090aa5885 100644 --- a/lib/util/term.c +++ b/lib/util/term.c @@ -244,7 +244,7 @@ sudo_term_noecho_v1(int fd) #ifdef VSTATUS term.c_cc[VSTATUS] = _POSIX_VDISABLE; #endif - if (tcsetattr_nobg(fd, TCSASOFT|TCSADRAIN, &term) == -1) { + if (tcsetattr_nobg(fd, TCSASOFT|TCSAFLUSH, &term) == -1) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO, "%s: tcsetattr(%d)", __func__, fd); goto unlock; @@ -358,8 +358,9 @@ unlock: * Returns true on success or false on failure. */ bool -sudo_term_cbreak_v1(int fd) +sudo_term_cbreak_v2(int fd, bool flush) { + const int flags = flush ? (TCSASOFT|TCSAFLUSH) : (TCSASOFT|TCSADRAIN); struct termios term = { 0 }; bool ret = false; debug_decl(sudo_term_cbreak, SUDO_DEBUG_UTIL); @@ -382,7 +383,7 @@ sudo_term_cbreak_v1(int fd) #ifdef VSTATUS term.c_cc[VSTATUS] = _POSIX_VDISABLE; #endif - if (tcsetattr_nobg(fd, TCSASOFT|TCSADRAIN, &term) == -1) { + if (tcsetattr_nobg(fd, flags, &term) == -1) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO, "%s: tcsetattr(%d)", __func__, fd); goto unlock; @@ -399,6 +400,12 @@ unlock: debug_return_bool(ret); } +bool +sudo_term_cbreak_v1(int fd) +{ + return sudo_term_cbreak_v2(fd, false); +} + /* * Copy terminal settings from one descriptor to another. * We cannot simply copy the struct termios as src and dst may be diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in index be01e6379..036314707 100644 --- a/lib/util/util.exp.in +++ b/lib/util/util.exp.in @@ -159,6 +159,7 @@ sudo_strtomode_v1 sudo_strtomode_v2 sudo_strtonum sudo_term_cbreak_v1 +sudo_term_cbreak_v2 sudo_term_copy_v1 sudo_term_eof sudo_term_erase diff --git a/src/tgetpass.c b/src/tgetpass.c index b883d9ec7..2006b09d2 100644 --- a/src/tgetpass.c +++ b/src/tgetpass.c @@ -185,7 +185,7 @@ restart: if (!ISSET(flags, TGP_ECHO)) { for (;;) { if (ISSET(flags, TGP_MASK)) - neednl = feedback = sudo_term_cbreak(input); + neednl = feedback = sudo_term_cbreak(input, true); else neednl = sudo_term_noecho(input); if (neednl || errno != EINTR)