Bugzilla – Bug 1023041
VUL-0: CVE-2017-2616: util-linux, coreutils: su PAM local SIGKILL DoS
Last modified: 2020-06-30 07:39:09 UTC
I just got a mail from Karel Žák, upstream maintainer of util-linux: From: Karel Zak <kzak@redhat.com> To: Werner Fink <werner@suse.de>, Andreas Henriksson <andreas@fatal.se>, Stanislav Brabec <sbrabec@suse.cz>, Mike Frysinger <vapier@gentoo.org>, Bruce Dubbs <bruce.dubbs@gmail.com>, secalert@redhat.com Subject: su(1) security issue Hi guys, (downstream maintainers and RH security guys), Tobias Stöckmann <tobias@stoeckmann.org> found a nice su(1) bug, see his description: If su is compiled with PAM support, it is possible for any local user to send SIGKILL to other processes with root privileges. There are only two conditions. First, the user must be able to perform su with a successful login. This does NOT have to be the root user, even using su with the same id is enough, e.g. "su $(whoami)". Second, SIGKILL can only be sent to processes which were executed after the su process. It is not possible to send SIGKILL to processes which were already running. I consider this as a security vulnerability, because I was able to write a proof of concept which unlocked a screen saver of another user this way. The complete original report is bellow. The bugfix patch is already committed to the upstream repository: https://github.com/karelzak/util-linux/commit/dffab154d29a288aa171ff50263ecc8f2e14a891 (the commit message is without any details...) Please, downstream maintainers don't share the information about this issue publicly. It would be better to do it by security community, but I still think that downstream should be informed now. IMHO affected are also old distros with su(1) from corecutils. Karel ********* *BEGIN OF SIGNED MESSAGE* ********* Hello Karel, hello Serge, I have discovered a security issue in su. Independently, the same bug exists in shadow as well as util-linux. Therefore, I have written this mail to both maintainers (which explains why you got it ). I would prefer a coordinated release of this, including the involvement of distro-watch etc. This mail went to: Karel Zak <kzak@redhat.com> PGP: B0C64D14301CC6EFAEDF60E4E4B71D5EEC39C284 and Serge Hallyn <serge.hallyn@ubuntu.com> PGP: F1D08DB778185BF784002DFFE9FEEA06A85E3F9D As both of you are involved with Linux distributions and the whole procedure of security release, I hope you can help me with doing this. SUMMARY ======= If su is compiled with PAM support, it is possible for any local user to send SIGKILL to other processes with root privileges. There are only two conditions. First, the user must be able to perform su with a successful login. This does NOT have to be the root user, even using su with the same id is enough, e.g. "su $(whoami)". Second, SIGKILL can only be sent to processes which were executed after the su process. It is not possible to send SIGKILL to processes which were already running. I consider this as a security vulnerability, because I was able to write a proof of concept which unlocked a screen saver of another user this way. DETAILS ======= When su started a shell or another program with the permissions of the target user, it performs waitpid() on the child's process id. While it waits, it also accepts signals, e.g. SIGTERM, which would merely set a flag called caught/caught_signal (this depends on the project). The problem arises when the child successfully finishes. On Unix systems, child processes turn into zombies until the parent process called wait() or waitpid(). As long as the zombie exists, the process id cannot be given to a new process. But su contains some logic to kill a child process when it received a signal on its own, e.g. SIGTERM. As such a signal can be received at any given time, it is possible to send such a signal _after_ waitpid() finished successfully. This in turn means that su will send SIGKILL to any kind of process that happens to have the same id as the child had before. It sounds like a very racy thing to do, but the attacker has multiple advantages. First, he can decide when to stop the child, as it is under his own control. Second, su can be suspended by SIGSTOP, which the attacker can send to the su process due the ownership (it's setuid). Third, the attacker knows exactly which pid will be killed, because the information can be easily retrieved while the child process is running. A successfully suspended su is therefore a loaded gun which is about to be triggered the moment su receives the SIGCONT signal... If the system does not offer process id randomisation, it is rather easy to fast-forward by constantly calling fork() and kill() until the very next fork call will yield the desired pid. Also, it is possible to keep multiple su processes ready in the background, so an attacker could have a small repertoire of killers around, when it's time to fire... SOLUTION ======== I have inlined patches which fix the issue at the end. Which one depends on the project you maintain (otherwise the mail is identical for you two). The fix is rather "simple", but I really really hope that you both take a very close look at them. What we have to do is to make sure that if waitpid() finished successfully, the child mustn't receive any more signals, because it's already gone. In the case of shadow, it takes a critical section to prevent SIGALRM from sending a signal to the child while we reset the child_pid. PROOF OF CONCEPT ================ I used this code to loop around the process id list: -------------------------getpid.c--------------------------------------- #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { pid_t cpid, pid; int wstatus; if (argc < 2) { fprintf(stderr, "usage: getpid pid\n"); return 1; } pid = atoi(argv[1]); if (pid < 1) { fprintf(stderr, "pid is invalid: %s\n", pid); return 1; } try_again: cpid = fork(); switch (cpid) { case -1: fprintf(stderr, "unable to fork\n"); return 1; case 0: execl("/bin/sleep", "sleep", "500000", NULL); _exit(1); default: if (cpid == pid) { printf("got pid %ld\n", (long) pid); while (waitpid(pid, &wstatus, 0) < 0) { if (errno == EINTR) continue; fprintf(stderr, "waitpid failed\n"); return 1; } printf("child exited\n"); } else { kill(cpid, SIGTERM); waitpid(cpid, &wstatus, 0); goto try_again; } break; } return 0; } -------------------------getpid.c--------------------------------------- Otherwise I was too lazy to automate the password handling in su, so instead I've inserted a delay after waitpid, which gave me enough time to prepare a process of another user which I wanted to kill. In my example, I did: userA | userB --------------------------------+------------------- $ su -c 'echo $$' userA | Password: | 21540 | pretend suspend, press enter... | | $ ./getpid 21540 | got pid 21540 ### enter pressed ### | | child exited $ _ | $ _ NEED HELP? ========== In case you have further questions, don't hesitate to ask me. If it's about coordinating all this, I would prefer a CC so everyone stays updated. With kind regards, Tobias PS: My PGP fingerprint is CDB24BD3BDDCBCBBAE5CB6207DB470F35B0B8B18 diff --git a/login-utils/su-common.c b/login-utils/su-common.c index 5aefd3fff..f9a749fc3 100644 --- a/login-utils/su-common.c +++ b/login-utils/su-common.c @@ -368,6 +368,7 @@ create_watching_parent (void) } else status = WEXITSTATUS (status); + child = -1; } else if (caught_signal) status = caught_signal + 128; @@ -377,7 +378,7 @@ create_watching_parent (void) else status = 1; - if (caught_signal) + if (caught_signal && child != -1) { fprintf (stderr, _("\nSession terminated, killing shell...")); kill (child, SIGTERM); @@ -387,9 +388,12 @@ create_watching_parent (void) if (caught_signal) { - sleep (2); - kill (child, SIGKILL); - fprintf (stderr, _(" ...killed.\n")); + if (child != -1) + { + sleep (2); + kill (child, SIGKILL); + fprintf (stderr, _(" ...killed.\n")); + } /* Let's terminate itself with the received signal. * ********* *END OF SIGNED MESSAGE* ********* -- Karel Zak <kzak@redhat.com> http://karelzak.blogspot.com
Attaching further discussion. Please let me know, whether one week is sufficient for CRD. From my side (backport of fixes in util-linux to SLE12 *), I can submit fixes just now. The rest depends on QA and coreutils backport. Date: Thu, 2 Feb 2017 04:52:12 -0500 From: Red Hat Product Security <secalert@redhat.com> Subject: [engineering.redhat.com #436002] su(1) security issue To: kzak@redhat.com CC: andreas@fatal.se, bruce.dubbs@gmail.com, sbrabec@suse.cz, vapier@gentoo.org, werner@suse.de ... skipping citation ... Hello Karel, Thank you for reporting this issue. Any idea on public disclosure date? Also do you need CVE or have you already requested one? Best Regards, -- Adam Mariš / Red Hat Product Security Date: Thu, 2 Feb 2017 12:01:42 +0100 From: Karel Zak <kzak@redhat.com> To: Red Hat Product Security <secalert@redhat.com> Cc: andreas@fatal.se, bruce.dubbs@gmail.com, sbrabec@suse.cz, vapier@gentoo.org, werner@suse.de Subject: Re: [engineering.redhat.com #436002] su(1) security issue On Thu, Feb 02, 2017 at 04:52:12AM -0500, Red Hat Product Security wrote: > Thank you for reporting this issue. Any idea on public disclosure date? I have bugfix, so it's all about time we all need to prepare erratas/updates packages. IMHO one week should be enough (if we really need embargo...) > Also do you need CVE or have you already requested one? I do not need CVE for anything, it's your playground guys There is Suse bug report about it: http://bugzilla.suse.com/show_bug.cgi?id=1023041 I have no feedback from another distros yet (but they are in CC:) Karel -- Karel Zak <kzak@redhat.com> http://karelzak.blogspot.com Date: Thu, 2 Feb 2017 10:09:44 -0500 From: Red Hat Product Security <secalert@redhat.com> To: kzak@redhat.com CC: andreas@fatal.se, bruce.dubbs@gmail.com, sbrabec@suse.cz, vapier@gentoo.org, werner@suse.de On Thu Feb 02 12:01:48 2017, kzak@redhat.com wrote: > On Thu, Feb 02, 2017 at 04:52:12AM -0500, Red Hat Product Security wrote: >> Thank you for reporting this issue. Any idea on public disclosure date? > > I have bugfix, so it's all about time we all need to prepare > erratas/updates packages. IMHO one week should be enough (if we really > need embargo...) > >> Also do you need CVE or have you already requested one? > > I do not need CVE for anything, it's your playground guys Well then please use CVE-2017-2616 for this issue. Best Regards, -- Adam Mariš / Red Hat Product Security
is public now https://www.kernel.org/pub/linux/utils/util-linux/v2.29/v2.29.2-ReleaseNotes
SUSE-SU-2017:0553-1: An update that solves two vulnerabilities and has 11 fixes is now available. Category: security (important) Bug References: 1008965,1012504,1012632,1019332,1020077,1023041,947494,966891,978993,982331,983164,987176,988361 CVE References: CVE-2016-5011,CVE-2017-2616 Sources used: SUSE Linux Enterprise Server for SAP 12 (src): python-libmount-2.25-24.10.3, util-linux-2.25-24.10.1, util-linux-systemd-2.25-24.10.1 SUSE Linux Enterprise Server 12-LTSS (src): python-libmount-2.25-24.10.3, util-linux-2.25-24.10.1, util-linux-systemd-2.25-24.10.1
SUSE-SU-2017:0554-1: An update that solves one vulnerability and has 6 fixes is now available. Category: security (important) Bug References: 1008965,1012504,1012632,1019332,1020077,1020985,1023041 CVE References: CVE-2017-2616 Sources used: SUSE Linux Enterprise Workstation Extension 12-SP2 (src): util-linux-2.28-44.3.1 SUSE Linux Enterprise Software Development Kit 12-SP2 (src): util-linux-2.28-44.3.1 SUSE Linux Enterprise Server for Raspberry Pi 12-SP2 (src): python-libmount-2.28-44.3.3, util-linux-2.28-44.3.1, util-linux-systemd-2.28-44.3.3 SUSE Linux Enterprise Server 12-SP2 (src): python-libmount-2.28-44.3.3, util-linux-2.28-44.3.1, util-linux-systemd-2.28-44.3.3 SUSE Linux Enterprise Desktop 12-SP2 (src): python-libmount-2.28-44.3.3, util-linux-2.28-44.3.1, util-linux-systemd-2.28-44.3.3
SUSE-SU-2017:0555-1: An update that solves one vulnerability and has 5 fixes is now available. Category: security (important) Bug References: 1008965,1012504,1012632,1019332,1020077,1023041 CVE References: CVE-2017-2616 Sources used: SUSE Linux Enterprise Workstation Extension 12-SP1 (src): util-linux-2.25-40.1 SUSE Linux Enterprise Software Development Kit 12-SP1 (src): util-linux-2.25-40.1 SUSE Linux Enterprise Server 12-SP1 (src): python-libmount-2.25-40.2, util-linux-2.25-40.1, util-linux-systemd-2.25-40.1 SUSE Linux Enterprise Desktop 12-SP1 (src): python-libmount-2.25-40.2, util-linux-2.25-40.1, util-linux-systemd-2.25-40.1
openSUSE-SU-2017:0589-1: An update that solves one vulnerability and has 6 fixes is now available. Category: security (important) Bug References: 1008965,1012504,1012632,1019332,1020077,1020985,1023041 CVE References: CVE-2017-2616 Sources used: openSUSE Leap 42.2 (src): python-libmount-2.28-10.2, util-linux-2.28-10.1, util-linux-systemd-2.28-10.1
openSUSE-SU-2017:0590-1: An update that solves one vulnerability and has 5 fixes is now available. Category: security (important) Bug References: 1008965,1012504,1012632,1019332,1020077,1023041 CVE References: CVE-2017-2616 Sources used: openSUSE Leap 42.1 (src): python-libmount-2.25-21.1, util-linux-2.25-21.1, util-linux-systemd-2.25-21.1
util-linux should be fixed in Leap 42.1, Leap 42.2, SLE12, SLE12 SP1, SLE12 SP2 and Tumbleweed. SLE11 and older are not affected, su is not present in util-linux there. Reassigning to coreutils maintainer to evaluate vulnerability of su in SLE11 and possibly SLE10.
Su in coreutils needs no changes as it used execve and not fork like su in util-linux and therefore doesn't need the special signal handling required when using fork.
Hi Philipp, (In reply to pth@suse.com from comment #17) > Su in coreutils needs no changes as it used execve and not fork like su in > util-linux and therefore doesn't need the special signal handling required > when using fork. can you please explain this to me in more detail? I had a look at the coreutils code for SLE-11-SP2 again in SUSE:SLE-11-SP2:Update/coreutils/coreutils-8.12/src/su.c and can't see how it's not affected. It's calling create_watching_parent(), and USE_PAM seems to be defined for the build. Thank you.
I'll have to let my co-maintainer and upstream coreutil maintainer answer that question, as it was his statement I was relaying. Berny, could you please chime in?
Sorry, it seems that I don't have access to build.suse.com [1], so I am/was looking into the upstream version at coreutils at that time [2], and there is no fork -> wait/waitpid, because main() calls run_shell() which in turn calls execv(). [1] 402: Account Unconfirmed [2] http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/su.c?h=v8.12&id=8c6a1d1281#n331 Of course the SUSE sources of that time may have diverged from upstream by patches for this or that, but I was assuming that it was still almost about the same. Have a nice day, Berny
I checked again and
(In reply to Philipp Thomas from comment #21) > I checked again and Your comment is truncated, but given that you reopened the bug I suspect there is still something to fix?
Yes, I had completely forgotten that although SLE11 SP2 got coreutils 8.12 su was still provided by it. Somehow I had connected corerutils 8.12 with su coming from util-linux. So as you wrote, the su in SLE11 SP2 needs the fix.
(In reply to Philipp Thomas from comment #23) Please submit for this codestream. Thank you
ping. Please submit
As openSUSE guy, I still don't have access to the SUSE bild service, but looking back at Base:System/coreutils rev 126, I see that the patch "coreutils-8.6-pam-support-for-su.diff" would need the tweaks as shown in the UL commit. Re-assigning to Raymund Will (as new SLE maintainer AFAIK).
Created attachment 762118 [details] Proposed patch for coreutils-8.12 from SLE11SP2 Thank you, Bernhard. Would you (or anyone on CC) be willing to review this patch? (It compiles, but is otherwise untested.)
Hi Raymund, hmm, the patch looks quite different from the original mentioned at the top if this issue. Where did you get the changes from (this is not mentioned in the patch)? Have a nice day, Berny
Raimund looked at the su code in util-linux for which the patch was done and noticed a few things that where missing from coreutils-8.6-pam-support-for-su.diff and added them (like saving and restoring signal handling). For me it looks like the patch implements exactly what is needed.
I agree: while the patch doesn't apply against the latest openSUSE sources [0], a visual comparison against latest upstream UL looks good to me as well. Thanks. [0] https://build.opensuse.org/package/show/Base:System/coreutils?rev=126
(In reply to Bernhard Voelker from comment #30) little clarification: > [...] doesn't apply against the latest openSUSE sources [...] s/latest openSUSE sources/& of version 8.12/
The latest openSUSE sources of version 8.12 are unfortunately lacking some SLE-patches, including 'coreutils-bnc#697897-setsid.patch'. But as 'su' is no longer part of maintained openSUSE 'coreutils' packages, this should be no problem, right?
SUSE-SU-2018:0866-1: An update that fixes one vulnerability is now available. Category: security (important) Bug References: 1023041 CVE References: CVE-2017-2616 Sources used: SUSE Linux Enterprise Server 11-SP4 (src): coreutils-8.12-6.25.33.3.1 SUSE Linux Enterprise Debuginfo 11-SP4 (src): coreutils-8.12-6.25.33.3.1
Done