Bug 1020601 - (CVE-2016-10156) VUL-0: CVE-2016-10156: systemd: world writable suid files local root vulnerability
(CVE-2016-10156)
VUL-0: CVE-2016-10156: systemd: world writable suid files local root vulnerab...
Status: RESOLVED FIXED
Classification: Novell Products
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents
unspecified
Other Other
: P2 - High : Major
: ---
Assigned To: Security Team bot
Security Team bot
https://smash.suse.de/issue/178819/
CVSSv2:NVD:CVE-2016-10156:7.2:(AV:L/A...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2017-01-18 10:45 UTC by Sebastian Krahmer
Modified: 2017-01-26 18:06 UTC (History)
8 users (show)

See Also:
Found By: Security Response Team
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Krahmer 2017-01-18 10:45:47 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::::::
Comment 1 Sebastian Krahmer 2017-01-18 10:49:15 UTC
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;
Comment 2 Sebastian Krahmer 2017-01-18 10:50:15 UTC
Apparently upstream failed to analyze the impact of this bug and so
it was silently fixed.
Comment 3 Marcus Meissner 2017-01-18 10:53:03 UTC
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.
Comment 4 Andreas Stieger 2017-01-18 13:05:47 UTC
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
Comment 5 Andreas Stieger 2017-01-18 13:06:45 UTC
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
Comment 6 Andreas Stieger 2017-01-18 13:08:41 UTC
systemctl daemon-reexec may apply the new binary directly
Comment 7 Sebastian Krahmer 2017-01-18 15:29:55 UTC
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.
Comment 8 Franck Bui 2017-01-19 07:51:32 UTC
(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 ?
Comment 9 Franck Bui 2017-01-19 07:57:25 UTC
(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.
Comment 10 Franck Bui 2017-01-19 07:58:43 UTC
(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 ?
Comment 11 Franck Bui 2017-01-19 08:03:58 UTC
(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.
Comment 12 Franck Bui 2017-01-19 10:33:29 UTC
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.
Comment 13 Sebastian Krahmer 2017-01-23 07:00:31 UTC
(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.
Comment 14 Franck Bui 2017-01-23 07:34:42 UTC
(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.
Comment 15 Sebastian Krahmer 2017-01-23 08:42:41 UTC
(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.
Comment 16 Andreas Stieger 2017-01-23 11:37:06 UTC
CVE-2016-10156 was assigned by Mitre
Comment 17 Franck Bui 2017-01-23 13:21:51 UTC
(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 ?
Comment 18 Sebastian Krahmer 2017-01-23 13:50:16 UTC
(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.
Comment 19 Franck Bui 2017-01-23 14:08:15 UTC
(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.
Comment 21 Marcus Meissner 2017-01-24 09:40:59 UTC
is public
Comment 22 Franck Bui 2017-01-24 10:05:17 UTC
(In reply to Marcus Meissner from comment #21)
> is public

Already ?
Comment 24 Swamp Workflow Management 2017-01-25 12:09:36 UTC
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
Comment 25 Franck Bui 2017-01-25 12:22:47 UTC
Closing as the fix is now released.
Comment 27 Andreas Stieger 2017-01-25 12:37:21 UTC
openSUSE Leap 42.2 update running in openSUSE:Maintenance:6307
Comment 28 Andreas Stieger 2017-01-25 18:01:08 UTC
release for openSUSE Leap 42.2
Comment 29 Swamp Workflow Management 2017-01-25 21:09:07 UTC
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