Skip to content

Commit fa8ffeb

Browse files
committed
Fix a buffer overflow when pwfeedback is enabled and input is a not a tty.
In getln() if the user enters ^U (erase line) and the write(2) fails, the remaining buffer size is reset but the current pointer is not. While here, fix an incorrect break for erase when write(2) fails. Also disable pwfeedback when input is not a tty as it cannot work. CVE-2019-18634 Credit: Joe Vennix from Apple Information Security.
1 parent 0fcb647 commit fa8ffeb

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

src/tgetpass.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ enum tgetpass_errval {
6161
static volatile sig_atomic_t signo[NSIG];
6262

6363
static void tgetpass_handler(int);
64-
static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
64+
static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
6565
static char *sudo_askpass(const char *, const char *);
6666

6767
static int
@@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout, int flags,
125125
static char buf[SUDO_CONV_REPL_MAX + 1];
126126
int i, input, output, save_errno, ttyfd;
127127
bool need_restart, neednl = false;
128+
bool feedback = ISSET(flags, TGP_MASK);
128129
enum tgetpass_errval errval;
129130
debug_decl(tgetpass, SUDO_DEBUG_CONV);
130131

@@ -180,7 +181,7 @@ tgetpass(const char *prompt, int timeout, int flags,
180181
*/
181182
if (!ISSET(flags, TGP_ECHO)) {
182183
for (;;) {
183-
if (ISSET(flags, TGP_MASK))
184+
if (feedback)
184185
neednl = sudo_term_cbreak(input);
185186
else
186187
neednl = sudo_term_noecho(input);
@@ -194,6 +195,9 @@ tgetpass(const char *prompt, int timeout, int flags,
194195
}
195196
}
196197
}
198+
/* Only use feedback mode when we can disable echo. */
199+
if (!neednl)
200+
feedback = false;
197201

198202
/*
199203
* Catch signals that would otherwise cause the user to end
@@ -224,7 +228,7 @@ tgetpass(const char *prompt, int timeout, int flags,
224228

225229
if (timeout > 0)
226230
alarm(timeout);
227-
pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
231+
pass = getln(input, buf, sizeof(buf), feedback, &errval);
228232
alarm(0);
229233
save_errno = errno;
230234

@@ -366,7 +370,7 @@ sudo_askpass(const char *askpass, const char *prompt)
366370
extern int sudo_term_eof, sudo_term_erase, sudo_term_kill;
367371

368372
static char *
369-
getln(int fd, char *buf, size_t bufsiz, int feedback,
373+
getln(int fd, char *buf, size_t bufsiz, bool feedback,
370374
enum tgetpass_errval *errval)
371375
{
372376
size_t left = bufsiz;
@@ -395,15 +399,15 @@ getln(int fd, char *buf, size_t bufsiz, int feedback,
395399
while (cp > buf) {
396400
if (write(fd, "\b \b", 3) == -1)
397401
break;
398-
--cp;
402+
cp--;
399403
}
404+
cp = buf;
400405
left = bufsiz;
401406
continue;
402407
} else if (c == sudo_term_erase) {
403408
if (cp > buf) {
404-
if (write(fd, "\b \b", 3) == -1)
405-
break;
406-
--cp;
409+
ignore_result(write(fd, "\b \b", 3));
410+
cp--;
407411
left++;
408412
}
409413
continue;

0 commit comments

Comments
 (0)