Bugzilla – Bug 940339
VUL-0: CVE-2015-5706: kernel: Use-after-free in path lookup
Last modified: 2016-04-27 19:43:41 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
bugbot adjusting priority
Doesn't affect any TD branch.
OK, should be easy.
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!
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?
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.
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...
The oss-security list is probably appropriate for this.