Bug 940339 - (CVE-2015-5706) VUL-0: CVE-2015-5706: kernel: Use-after-free in path lookup
(CVE-2015-5706)
VUL-0: CVE-2015-5706: kernel: Use-after-free in path lookup
Status: RESOLVED INVALID
Classification: Novell Products
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents
unspecified
Other Other
: P3 - Medium : Normal
: ---
Assigned To: Security Team bot
Security Team bot
https://smash.suse.de/issue/119405/
CVSSv2:NVD:CVE-2015-5706:4.6:(AV:L/AC...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2015-08-03 11:29 UTC by Johannes Segitz
Modified: 2016-04-27 19:43 UTC (History)
7 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 Johannes Segitz 2015-08-03 11:29:17 UTC
CVE-2015-5706

From: Ben Hutchings 

Bug was introduced in Linux 3.11-rc1 by:

commit 60545d0d4610b02e55f65d141c95b18ccf855b6e
Author: Al Viro <viro () zeniv linux org uk>
Date:   Fri Jun 7 01:20:27 2013 -0400

    [O_TMPFILE] it's still short a few helpers, but infrastructure should be OK now...
    
    Signed-off-by: Al Viro <viro () zeniv linux org uk>

Fixed in 4.1-rc3 by:

commit f15133df088ecadd141ea1907f2c96df67c729f0
Author: Al Viro <viro () zeniv linux org uk>
Date:   Fri May 8 22:53:15 2015 -0400

    path_openat(): fix double fput()
    
    path_openat() jumps to the wrong place after do_tmpfile() - it has
    already done path_cleanup() (as part of path_lookupat() called by
    do_tmpfile()), so doing that again can lead to double fput().
    
    Cc: stable () vger kernel org  # v3.11+
    Signed-off-by: Al Viro <viro () zeniv linux org uk>

Thanks to Brad Spengler for pointing this out:<
https://twitter.com/grsecurity/status/597127122910490624>

The fix was also included in the following stable releases:

v3.13.11-ckt22: d8ef4f4c5465 path_openat(): fix double fput()
v3.16.7-ckt12: bedf03d0b88d path_openat(): fix double fput()
v3.18.15: f42b455331b5 path_openat(): fix double fput()
v3.19.8-ckt1: cf32bb6d9d18 path_openat(): fix double fput()
v4.0.4: 335d3678d60d path_openat(): fix double fput()

SLE 12 seems to be affected.

References:
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-5706
http://seclists.org/oss-sec/2015/q3/277
Comment 1 Swamp Workflow Management 2015-08-03 22:00:27 UTC
bugbot adjusting priority
Comment 2 Michal Hocko 2015-08-04 07:53:16 UTC
Doesn't affect any TD branch.
Comment 4 Jan Kara 2015-08-14 08:51:23 UTC
OK, should be easy.
Comment 5 Jan Kara 2015-08-14 11:00:51 UTC
Hmm, so I can see the problem in the upstream kernel before the fix was applied but I don't think there's a problem in 3.11, 3.12, or even 3.16 kernel. That being said the cleanup path is somewhat convoluted so I may be missing something.

If I understand it right, the problem is with handling 'base' pointer where additional fput() can happen prior commit f15133df08 "path_openat(): fix double fput()" because nd->base has been already 'fput' in path_cleanup() at the end of path_lookupat(). However upto commit 5e53084d7734 "path_init(): store the "base" pointer to file in nameidata itself" which was merged in 3.19-rc1 'base' was just a local variable properly initialized to NULL so the problem didn't exist.

And there's also the cleanup of nd->root which seems to properly happen in path_lookupat() and so is superfluous in path_openat() but again this is harmless because we notice nd->root is already cleaned up and won't do anything.

Neil, can you please double check before we close this? Thanks!
Comment 6 Neil Brown 2015-08-16 23:55:32 UTC
I agree Jack.

Bug was introduced in v3.19-rc1 by

Commit: 5e53084d7734 ("path_init(): store the "base" pointer to file in nameidata itself")

Prior to this commit, 'base' was initialised to NULL in path_openat() and if do_tmpfile() failed, the code:
  if (base)
     fput(base);

would correctly do nothing.

After this patch, 'base' is a field in 'nd', and nd->base isn't initialised until path_init() is called.  So if do_tmpfile() (called before patH_init()) fails, the code
   if (nd->base)
     fput(nd->base);

will test an uninitialised field, and may call fput() on it.  So it isn't really a "double fput", but a "use uninitialised variable".

So v3.19 and v4.0 are the only vulnerable kernels.

Should we tell the CVE people?
Comment 7 Neil Brown 2015-08-17 01:08:54 UTC
No.... I missed something there.

do_tmpfile() always calls path_lookupat() which always calls path_init().
So nd->base will be initialised correctly.

Let me try again...

The bug was (still) introduced by 

Commit: 5e53084d7734 ("path_init(): store the "base" pointer to file in nameidata itself")

Prior to that commit, but path_lookupat() and path_openat() (and path_mountpoint()) had a local variable 'base', which was initialised to NULL
at the top, and the had fput() called on it at the end.

That patch moved all three 'base' variables into 'nd'.
Because path_openat() calls do_tmpfile() which calls path_lookupat(), path_openat() and path_lookupat() now use the *same* ->base where previously they used different 'base' variables.

As nd->base is not zeroed after it is fput() it is possible that path_lookupat and path_openat both try to fput the same  'base'.

So it is a double-fput, but only 3.19 and 4.0 are affected by that.

The bugfix skips over both the fput of 'base' and a possible path_put of nd->root.
We can *not* end up with a double-path_put because when path_lookupat() calls path_put, it also sets nd->root.mnt to NULL, so path_openat() will not call path_put().

So just one bug, introduced in v3.19.  Bugfix appears safe, but is unnecessary.
Comment 8 Jan Kara 2015-08-17 08:22:17 UTC
OK, so we agree. Thanks for verification Neil. We can notify CVE people just that others don't have to be bothered with backporting the fix. Anyone knows where?

Otherwise this bug can be closed as it doesn't affect any of our kernels. Reassigning to security guys...
Comment 9 Sebastian Krahmer 2015-08-17 12:54:18 UTC
The oss-security list is probably appropriate for this.