Bugzilla – Bug 1020601
VUL-0: CVE-2016-10156: systemd: world writable suid files local root vulnerability
Last modified: 2017-01-26 18:06:05 UTC
systemd creates world writable suid files that allows attackers to dump binaries into it and execute code as root easily: krahmer@f222:~> ls -la /var/lib/systemd/timers/ insgesamt 12 drwxr-xr-x 2 root root 4096 18. Jan 11:34 . drwxr-xr-x 7 root root 4096 18. Jan 11:34 .. -rwsrwsrwt 1 root root 155 18. Jan 11:37 stamp-fstrim.timer krahmer@f222:~> /var/lib/systemd/timers/stamp-fstrim.timer /bin/sh -p sh-4.3# grep bin /etc/shadow bin:*:15288::::::
Marcus and me believe this is due to: 321 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { 322 _cleanup_close_ int fd; 323 int r; 324 325 assert(path); 326 327 if (parents) 328 mkdir_parents(path, 0755); 329 330 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); 331 if (fd < 0) 332 return -errno; 333 where mode_t is unsigned and therefore the file gets created with all bits set (including suid bit). Apparently this was fixed by systemd upstream as a DoS issue: commit 06eeacb6fe029804f296b065b3ce91e796e1cd0e Author: Mantas Mikulėnas <grawity@gmail.com> Date: Fri Jan 29 23:36:08 2016 +0200 basic: fix touch() creating files with 07777 mode mode_t is unsigned, so MODE_INVALID < 0 can never be true. This fixes a possible DoS where any user could fill /run by writing to a world-writable /run/systemd/show-status. diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index d31bd6e..61b651b 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -341,7 +341,8 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi if (parents) mkdir_parents(path, 0755); - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, + (mode == 0 || mode == MODE_INVALID) ? 0644 : mode); if (fd < 0) return -errno;
Apparently upstream failed to analyze the impact of this bug and so it was silently fixed.
introduced by: commit ee735086f8670be1591fa9593e80dd60163a7a2f Author: Lennart Poettering <lennart@poettering.net> Date: Wed Nov 11 22:54:56 2015 +0100 util-lib: use MODE_INVALID as invalid value for mode_t everywhere The problem seems to be in v228 only.
package compatibility notes, also for QA: As the world writable suid root files are persistent in the filesystem, updating the package and replacing the systemd binary will merely prevent them from being created again. The maintenance update will thus be marked as requiring reboot. An rpm %post stanza may adjust the permissions of any files that may be there (rather than removing genunine timers) The desired permissions are 0644, specifically the lack of suid root while being world writable. Note that the final element of /var/lib/systemd/timers may not even exist, the scriptlet should not error out in this case. However, there is a time window after the rpm scriptlet before a reboot where the offending files may be created again. It can be argued that we should not leave the impression that the rpm scriptlet is guaranteed to cover this. Test case 1: * Touch a world readable suid root file in /var/lib/systemd/timers/ * package update itself must remove it Test case 2: * update package, do not reboot * Touch a world readable suid root file in /var/lib/systemd/timers/ * reboot * file must be removed Test case 3: * After update and reboot, activating a (new) timer does not create a world-readable suid root files
s/removed/permissions adjusted/ Test case 1: * Touch a world readable suid root file in /var/lib/systemd/timers/ * package update itself must adjust permissions Test case 2: * update package, do not reboot * Touch a world readable suid root file in /var/lib/systemd/timers/ * reboot * file must have permissions adjusted Test case 3: * After update and reboot * activating a (new) timer does not create a world-readable suid root files
systemctl daemon-reexec may apply the new binary directly
Note that there may be other files (the "known unknowns") like /run/systemd/journal/flushed that are created with wrong mode, so making sure that no such files exist anymore, could be a bit tricky.
(In reply to Sebastian Krahmer from comment #0) > systemd creates world writable suid files that allows > attackers to dump binaries into it and execute code as root easily: > Just out of curiosity, the setuid bit seems to be automatically cleared by some tools like cp, dd, bash... how one can dump a binary into a world writable suid file without clearing the suid bit ?
(In reply to Marcus Meissner from comment #3) > > The problem seems to be in v228 only. Indeed. As a consequence: - a system upgrading from SP[01] to SP2 won't be affected unless the permanent timers have been created after upgrading to SP2. - a brand new SP2 installation will be affected.
(In reply to Sebastian Krahmer from comment #7) > Note that there may be other files (the "known unknowns") > like /run/systemd/journal/flushed that are created with wrong mode, > so making sure that no such files exist anymore, could be a bit tricky. Hm /run (as well as /var/run) is usually mounted with the "nosuid" option. Isn't it the case for SLE12 ?
(In reply to Andreas Stieger from comment #5) > s/removed/permissions adjusted/ > > Test case 1: > > * Touch a world readable suid root file in /var/lib/systemd/timers/ > * package update itself must adjust permissions > > Test case 2: > * update package, do not reboot > * Touch a world readable suid root file in /var/lib/systemd/timers/ I think instead of creating a dummy timer file manually, we should instead use a dummy timer unit and an associated dummy service and start the timer so systemd is creating itself the timer files. Because the fixes in systemd are not supposed to adjust permissions not created by systemd. > * reboot > * file must have permissions adjusted > > Test case 3: > * After update and reboot > * activating a (new) timer does not create a world-readable suid root files You might want to add another test case: Test case 4: * install SP2 * file must have permissions adjusted in order to make sure that fixed systemd is always used on new installations.
The following project should contain the fix for this issue and will be submitted for the next maintenance release of SP2. Should I submit now or do anybody want to give it a test ? Thanks. PS: the fix to handle existing files with dangerous permissions will also be included in Factory.
(In reply to Franck Bui from comment #8) > (In reply to Sebastian Krahmer from comment #0) > > systemd creates world writable suid files that allows > > attackers to dump binaries into it and execute code as root easily: > > > > Just out of curiosity, the setuid bit seems to be automatically cleared by > some tools like cp, dd, bash... how one can dump a binary into a world > writable suid file without clearing the suid bit ? Thats probably why the systemd maintainers flagged it as DoS. A description plus PoC on how one can dump arbitrary code into world writable suid/sgid files without clearing the bit can be found here: http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ Its for setgid dirs, but it also works for suid files. Can you paste a "grep /var /proc/mounts" to check whether its indeed nosuid for SLE12? On Leap, it wasnt mounted nosuid.
(In reply to Sebastian Krahmer from comment #13) > > Thats probably why the systemd maintainers flagged it as DoS. > A description plus PoC on how one can dump arbitrary code > into world writable suid/sgid files without clearing the > bit can be found here: > > http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ > > Its for setgid dirs, but it also works for suid files. Thanks for the pointer I'll have a look. > > Can you paste a "grep /var /proc/mounts" to check whether its indeed nosuid > for SLE12? On Leap, it wasnt mounted nosuid. I was mentioning /run and /var/run in comment #10 so I'm not sure why you're asking for /var here.
(In reply to Franck Bui from comment #10) > (In reply to Sebastian Krahmer from comment #7) > > Note that there may be other files (the "known unknowns") > > like /run/systemd/journal/flushed that are created with wrong mode, > > so making sure that no such files exist anymore, could be a bit tricky. > > Hm /run (as well as /var/run) is usually mounted with the "nosuid" option. > > Isn't it the case for SLE12 ? Either way, it would be good to have a solution to clean up any of the left files.
CVE-2016-10156 was assigned by Mitre
(In reply to Sebastian Krahmer from comment #15) > Either way, it would be good to have a solution to clean up any of > the left files. /run uses the "nosuid" option and it's mounted by systemd during system boot, so any files in this directory shouldn't be a problem. I grepped over systemd source code with: $ git grep "touch_file(.*MODE_INVALID)\|touch(" SLE12-SP2 and the only places I could have found are: - /run/systemd/* /run has the "nosuid" option so those should be fine and permissions will be adjusted on the next reboot. - /var/lib/systemd/linger/* Created by logind which run with umask(0022), so this file is not world writable either. However the setuid will be removed on the next package update in order to not left this file with the setuid bit indefinitely. Permissions of existing timestamp files are adjusted on next package update. - /var/lib/systemd/timers/*.timer Permissions of existing timestamp files are adjusted on next package update. @Sebastian, could you answer question from comment #12 ?
(In reply to Franck Bui from comment #12) > The following project should contain the fix for this issue and will be > submitted for the next maintenance release of SP2. > > Should I submit now or do anybody want to give it a test ? > I assume that its the upstream patch, so it should be safe to be submitted now. It will go through QA anyway.
(In reply to Sebastian Krahmer from comment #18) > > I assume that its the upstream patch, so it should be safe to be > submitted now. It will go through QA anyway. It's the upstream patch and also some permission adjustments (described in comment #17) made in %post of systemd.spec. I'll submit it.
is public
(In reply to Marcus Meissner from comment #21) > is public Already ?
SUSE-SU-2017:0279-1: An update that solves one vulnerability and has four fixes is now available. Category: security (important) Bug References: 1012266,1014560,1014566,1020601,997682 CVE References: CVE-2016-10156 Sources used: SUSE Linux Enterprise Software Development Kit 12-SP2 (src): systemd-228-132.1 SUSE Linux Enterprise Server for Raspberry Pi 12-SP2 (src): systemd-228-132.1 SUSE Linux Enterprise Server 12-SP2 (src): systemd-228-132.1 SUSE Linux Enterprise Desktop 12-SP2 (src): systemd-228-132.1
Closing as the fix is now released.
openSUSE Leap 42.2 update running in openSUSE:Maintenance:6307
release for openSUSE Leap 42.2
openSUSE-SU-2017:0287-1: An update that solves one vulnerability and has four fixes is now available. Category: security (important) Bug References: 1012266,1014560,1014566,1020601,997682 CVE References: CVE-2016-10156 Sources used: openSUSE Leap 42.2 (src): systemd-228-22.1, systemd-mini-228-22.1