Skip to content

Commit

Permalink
Fix a buffer overflow when pwfeedback is enabled and input is a not a…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
millert committed Jan 30, 2020
1 parent 0fcb647 commit fa8ffeb
Showing 1 changed file with 12 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/tgetpass.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ enum tgetpass_errval {
static volatile sig_atomic_t signo[NSIG];

static void tgetpass_handler(int);
static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
static char *sudo_askpass(const char *, const char *);

static int
Expand Down Expand Up @@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout, int flags,
static char buf[SUDO_CONV_REPL_MAX + 1];
int i, input, output, save_errno, ttyfd;
bool need_restart, neednl = false;
bool feedback = ISSET(flags, TGP_MASK);
enum tgetpass_errval errval;
debug_decl(tgetpass, SUDO_DEBUG_CONV);

Expand Down Expand Up @@ -180,7 +181,7 @@ tgetpass(const char *prompt, int timeout, int flags,
*/
if (!ISSET(flags, TGP_ECHO)) {
for (;;) {
if (ISSET(flags, TGP_MASK))
if (feedback)
neednl = sudo_term_cbreak(input);
else
neednl = sudo_term_noecho(input);
Expand All @@ -194,6 +195,9 @@ tgetpass(const char *prompt, int timeout, int flags,
}
}
}
/* Only use feedback mode when we can disable echo. */
if (!neednl)
feedback = false;

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

if (timeout > 0)
alarm(timeout);
pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
pass = getln(input, buf, sizeof(buf), feedback, &errval);
alarm(0);
save_errno = errno;

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

static char *
getln(int fd, char *buf, size_t bufsiz, int feedback,
getln(int fd, char *buf, size_t bufsiz, bool feedback,
enum tgetpass_errval *errval)
{
size_t left = bufsiz;
Expand Down Expand Up @@ -395,15 +399,15 @@ getln(int fd, char *buf, size_t bufsiz, int feedback,
while (cp > buf) {
if (write(fd, "\b \b", 3) == -1)
break;
--cp;
cp--;
}
cp = buf;
left = bufsiz;
continue;
} else if (c == sudo_term_erase) {
if (cp > buf) {
if (write(fd, "\b \b", 3) == -1)
break;
--cp;
ignore_result(write(fd, "\b \b", 3));
cp--;
left++;
}
continue;
Expand Down

0 comments on commit fa8ffeb

Please sign in to comment.