diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch new file mode 100644 index 0000000..5b71919 --- /dev/null +++ b/SOURCES/sudo-1.8.29-CVE-2019-18634-part1.patch @@ -0,0 +1,158 @@ +diff -up ./src/tgetpass.c.bla ./src/tgetpass.c +--- ./src/tgetpass.c.bla 2018-08-18 16:10:15.000000000 +0200 ++++ ./src/tgetpass.c 2020-02-05 17:15:16.216904891 +0100 +@@ -44,11 +44,18 @@ + #include "sudo.h" + #include "sudo_plugin.h" + ++enum tgetpass_errval { ++ TGP_ERRVAL_NOERROR, ++ TGP_ERRVAL_TIMEOUT, ++ TGP_ERRVAL_NOPASSWORD, ++ TGP_ERRVAL_READERROR ++}; ++ + static volatile sig_atomic_t signo[NSIG]; + + static bool tty_present(void); + static void tgetpass_handler(int); +-static char *getln(int, char *, size_t, int); ++static char *getln(int, char *, size_t, int, enum tgetpass_errval *); + static char *sudo_askpass(const char *, const char *); + + static int +@@ -77,6 +84,27 @@ suspend(int signo, struct sudo_conv_call + debug_return_int(ret); + } + ++static void ++tgetpass_display_error(enum tgetpass_errval errval) ++{ ++ debug_decl(tgetpass_display_error, SUDO_DEBUG_CONV) ++ ++ switch (errval) { ++ case TGP_ERRVAL_NOERROR: ++ break; ++ case TGP_ERRVAL_TIMEOUT: ++ sudo_warnx(U_("timed out reading password")); ++ break; ++ case TGP_ERRVAL_NOPASSWORD: ++ sudo_warnx(U_("no password was provided")); ++ break; ++ case TGP_ERRVAL_READERROR: ++ sudo_warn(U_("unable to read password")); ++ break; ++ } ++ debug_return; ++} ++ + /* + * Like getpass(3) but with timeout and echo flags. + */ +@@ -90,6 +118,7 @@ tgetpass(const char *prompt, int timeout + static const char *askpass; + static char buf[SUDO_CONV_REPL_MAX + 1]; + int i, input, output, save_errno, neednl = 0, need_restart; ++ enum tgetpass_errval errval; + debug_decl(tgetpass, SUDO_DEBUG_CONV) + + (void) fflush(stdout); +@@ -175,7 +204,7 @@ restart: + + if (timeout > 0) + alarm(timeout); +- pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK)); ++ pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval); + alarm(0); + save_errno = errno; + +@@ -183,6 +212,7 @@ restart: + if (write(output, "\n", 1) == -1) + goto restore; + } ++ tgetpass_display_error(errval); + + restore: + /* Restore old signal handlers. */ +@@ -210,6 +240,8 @@ restore: + for (i = 0; i < NSIG; i++) { + if (signo[i]) { + switch (i) { ++ case SIGALRM: ++ break; + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: +@@ -239,6 +271,7 @@ sudo_askpass(const char *askpass, const + { + static char buf[SUDO_CONV_REPL_MAX + 1], *pass; + struct sigaction sa, savechld; ++ enum tgetpass_errval errval; + int pfd[2], status; + pid_t child; + debug_decl(sudo_askpass, SUDO_DEBUG_CONV) +@@ -281,9 +314,11 @@ sudo_askpass(const char *askpass, const + + /* Get response from child (askpass). */ + (void) close(pfd[1]); +- pass = getln(pfd[0], buf, sizeof(buf), 0); ++ pass = getln(pfd[0], buf, sizeof(buf), 0, &errval); + (void) close(pfd[0]); + ++ tgetpass_display_error(errval); ++ + /* Wait for child to exit. */ + for (;;) { + pid_t rv = waitpid(child, &status, 0); +@@ -305,7 +340,8 @@ sudo_askpass(const char *askpass, const + extern int 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, int feedback, ++ enum tgetpass_errval *errval) + { + size_t left = bufsiz; + ssize_t nr = -1; +@@ -313,7 +349,10 @@ getln(int fd, char *buf, size_t bufsiz, + char c = '\0'; + debug_decl(getln, SUDO_DEBUG_CONV) + ++ *errval = TGP_ERRVAL_NOERROR; ++ + if (left == 0) { ++ *errval = TGP_ERRVAL_READERROR; + errno = EINVAL; + debug_return_str(NULL); /* sanity */ + } +@@ -354,14 +393,27 @@ getln(int fd, char *buf, size_t bufsiz, + } + } + +- debug_return_str_masked(nr == 1 ? buf : NULL); ++ if (nr != 1) { ++ if (nr == 0) { ++ *errval = TGP_ERRVAL_NOPASSWORD; ++ } else if (nr == -1) { ++ if (errno == EINTR) { ++ if (signo[SIGALRM] == 1) ++ *errval = TGP_ERRVAL_TIMEOUT; ++ } else { ++ *errval = TGP_ERRVAL_READERROR; ++ } ++ } ++ debug_return_str(NULL); ++ } ++ ++ debug_return_str_masked(buf); + } + + static void + tgetpass_handler(int s) + { +- if (s != SIGALRM) +- signo[s] = 1; ++ signo[s] = 1; + } + + static bool diff --git a/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch b/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch new file mode 100644 index 0000000..86743ba --- /dev/null +++ b/SOURCES/sudo-1.8.29-CVE-2019-18634-part2.patch @@ -0,0 +1,77 @@ +diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c +--- ./src/tgetpass.c.CVE-2019-18634 2020-02-05 17:16:07.601420697 +0100 ++++ ./src/tgetpass.c 2020-02-05 17:22:34.206301510 +0100 +@@ -55,7 +55,7 @@ static volatile sig_atomic_t signo[NSIG] + + static bool tty_present(void); + 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 +@@ -118,6 +118,7 @@ tgetpass(const char *prompt, int timeout + static const char *askpass; + static char buf[SUDO_CONV_REPL_MAX + 1]; + int i, input, output, save_errno, neednl = 0, need_restart; ++ bool feedback = ISSET(flags, TGP_MASK); + enum tgetpass_errval errval; + debug_decl(tgetpass, SUDO_DEBUG_CONV) + +@@ -165,7 +166,7 @@ restart: + */ + if (!ISSET(flags, TGP_ECHO)) { + for (;;) { +- if (ISSET(flags, TGP_MASK)) ++ if (feedback) + neednl = sudo_term_cbreak(input); + else + neednl = sudo_term_noecho(input); +@@ -179,6 +180,9 @@ restart: + } + } + } ++ /* Only use feedback mode when we can disable echo. */ ++ if (!neednl) ++ feedback = false; + + /* + * Catch signals that would otherwise cause the user to end +@@ -204,7 +208,7 @@ restart: + + 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; + +@@ -340,7 +344,7 @@ sudo_askpass(const char *askpass, const + extern int 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; +@@ -366,15 +370,15 @@ getln(int fd, char *buf, size_t bufsiz, + 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; diff --git a/SPECS/sudo.spec b/SPECS/sudo.spec index b470367..8c4abb5 100644 --- a/SPECS/sudo.spec +++ b/SPECS/sudo.spec @@ -1,7 +1,7 @@ Summary: Allows restricted root access for specified users Name: sudo Version: 1.8.23 -Release: 4%{?dist}.1 +Release: 4%{?dist}.2 License: ISC Group: Applications/System URL: http://www.courtesan.com/sudo/ @@ -61,6 +61,10 @@ Patch11: sudo-1.8.23-who-am-i.patch Patch12: sudo-1.8.28-CVE-strtouid.patch Patch13: sudo-1.8.28-CVE-strtouid-test.patch +# 1798094 - CVE-2019-18634 sudo: Stack based buffer overflow in when pwfeedback is enabled [rhel-7.7.z] +Patch14: sudo-1.8.29-CVE-2019-18634-part1.patch +Patch15: sudo-1.8.29-CVE-2019-18634-part2.patch + %description Sudo (superuser do) allows a system administrator to give certain users (or groups of users) the ability to run some (or all) commands @@ -100,6 +104,9 @@ plugins that use %{name}. %patch12 -p1 -b .CVE-strtouid %patch13 -p1 -b .CVE-strtouid-test +%patch14 -p1 -b .CVE-2019-18634-part1 +%patch15 -p1 -b .CVE-2019-18634-part2 + %build autoreconf -I m4 -fv --install @@ -237,6 +244,11 @@ rm -rf %{buildroot} %{_mandir}/man8/sudo_plugin.8* %changelog +* Thu Feb 06 2020 Radovan Sroka 1.8.23-4.2 +- RHEL 7.7.z +- fixed CVE-2019-18634 + Resolves: rhbz#1798094 + * Wed Oct 16 2019 Radovan Sroka 1.8.23-4.1 - RHEL-7.7.z - fixed CVE-2019-14287