Brad Bishop | d5ae7d9 | 2018-06-14 09:52:03 -0700 | [diff] [blame] | 1 | shadow-4.2.1: Fix CVE-2017-2616 |
| 2 | |
| 3 | [No upstream tracking] -- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=855943 |
| 4 | |
| 5 | su: properly clear child PID |
| 6 | |
| 7 | If su is compiled with PAM support, it is possible for any local user |
| 8 | to send SIGKILL to other processes with root privileges. There are |
| 9 | only two conditions. First, the user must be able to perform su with |
| 10 | a successful login. This does NOT have to be the root user, even using |
| 11 | su with the same id is enough, e.g. "su $(whoami)". Second, SIGKILL |
| 12 | can only be sent to processes which were executed after the su process. |
| 13 | It is not possible to send SIGKILL to processes which were already |
| 14 | running. I consider this as a security vulnerability, because I was |
| 15 | able to write a proof of concept which unlocked a screen saver of |
| 16 | another user this way. |
| 17 | |
| 18 | Upstream-Status: Backport [https://github.com/shadow-maint/shadow/commit/08fd4b69e84364677a10e519ccb25b71710ee686] |
| 19 | CVE: CVE-2017-2616 |
| 20 | bug: 855943 |
| 21 | Signed-off-by: Andrej Valek <andrej.valek@siemens.com> |
| 22 | |
| 23 | diff --git a/src/su.c b/src/su.c |
| 24 | index 3704217..1efcd61 100644 |
| 25 | --- a/src/su.c |
| 26 | +++ b/src/su.c |
| 27 | @@ -363,20 +363,35 @@ static void prepare_pam_close_session (void) |
| 28 | /* wake child when resumed */ |
| 29 | kill (pid, SIGCONT); |
| 30 | stop = false; |
| 31 | + } else { |
| 32 | + pid_child = 0; |
| 33 | } |
| 34 | } while (!stop); |
| 35 | } |
| 36 | |
| 37 | - if (0 != caught) { |
| 38 | + if (0 != caught && 0 != pid_child) { |
| 39 | (void) fputs ("\n", stderr); |
| 40 | (void) fputs (_("Session terminated, terminating shell..."), |
| 41 | stderr); |
| 42 | (void) kill (-pid_child, caught); |
| 43 | |
| 44 | (void) signal (SIGALRM, kill_child); |
| 45 | + (void) signal (SIGCHLD, catch_signals); |
| 46 | (void) alarm (2); |
| 47 | |
| 48 | - (void) wait (&status); |
| 49 | + sigemptyset (&ourset); |
| 50 | + if ((sigaddset (&ourset, SIGALRM) != 0) |
| 51 | + || (sigprocmask (SIG_BLOCK, &ourset, NULL) != 0)) { |
| 52 | + fprintf (stderr, _("%s: signal masking malfunction\n"), Prog); |
| 53 | + kill_child (0); |
| 54 | + } else { |
| 55 | + while (0 == waitpid (pid_child, &status, WNOHANG)) { |
| 56 | + sigsuspend (&ourset); |
| 57 | + } |
| 58 | + pid_child = 0; |
| 59 | + (void) sigprocmask (SIG_UNBLOCK, &ourset, NULL); |
| 60 | + } |
| 61 | + |
| 62 | (void) fputs (_(" ...terminated.\n"), stderr); |
| 63 | } |
| 64 | |