Bug 472325 (CVE-2008-5182)

Summary: CVE-2008-5182 kernel: fix inotify watch removal/umount races
Product: [Other] Security Response Reporter: Eugene Teo (Security Response) <eteo>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: anton, aviro, bhu, dannf, dhoward, jbacik, jpirko, lgoncalv, lwang, mjc, rcvalle, sgrubb, williams
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard: impact=important,source=lkml,reported=20081120,public=20081115,cvss2=7.2/AV:L/AC:L/Au:N/C:C/I:C/A:C,cwe=CWE-662->CWE-362->CWE-672->CWE-476
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2010-12-21 12:53:01 EST Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---
Bug Depends On: 472327, 472328, 472329    
Bug Blocks:    
Attachments:
Description Flags
Proposed patch for real-time kernel none

Description Eugene Teo (Security Response) 2008-11-19 22:29:21 EST
From: Al Viro <viro@ZenIV.linux.org.uk>

Inotify watch removals suck violently.

To kick the watch out we need (in this order) inode->inotify_mutex and ih->mutex.  That's fine if we have a hold on inode; however, for all other cases we need to make damn sure we don't race with umount.  We can *NOT* just grab a reference to a watch - inotify_unmount_inodes() will happily sail past it and we'll end with reference to inode potentially outliving its superblock.

Ideally we just want to grab an active reference to superblock if we can; that will make sure we won't go into inotify_umount_inodes() until we are done.  Cleanup is just deactivate_super().

However, that leaves a messy case - what if we *are* racing with umount() and active references to superblock can't be acquired anymore? We can bump ->s_count, grab ->s_umount, which will almost certainly wait until the superblock is shut down and the watch in question is pining for fjords.  That's fine, but there is a problem - we might have hit the window between ->s_active getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock is past the point of no return and is heading for shutdown) and the moment when deactivate_super() acquires ->s_umount.

We could just do drop_super() yield() and retry, but that's rather antisocial and this stuff is luser-triggerable.  OTOH, having grabbed ->s_umount and having found that we'd got there first (i.e.  that ->s_root is non-NULL) we know that we won't race with inotify_umount_inodes().

So we could grab a reference to watch and do the rest as above, just with drop_super() instead of deactivate_super(), right? Wrong.  We had to drop ih->mutex before we could grab ->s_umount.  So the watch could've been gone already.

That still can be dealt with - we need to save watch->wd, do idr_find() and compare its result with our pointer.  If they match, we either have the damn thing still alive or we'd lost not one but two races at once, the watch had been killed and a new one got created with the same ->wd at the same address.  That couldn't have happened in inotify_destroy(), but inotify_rm_wd() could run into that.  Still, "new one got created" is not a problem - we have every right to kill it or leave it alone, whatever's more convenient.

So we can use idr_find(...) == watch && watch->inode->i_sb == sb as "grab it and kill it" check.  If it's been our original watch, we are fine, if it's a newcomer - nevermind, just pretend that we'd won the race and kill the fscker anyway; we are safe since we know that its superblock won't be going away.

And yes, this is far beyond mere "not very pretty"; so's the entire concept of inotify to start with.
Comment 5 Eugene Teo (Security Response) 2008-11-27 03:19:12 EST
Created attachment 324842 [details]
Proposed patch for real-time kernel

Luis, kindly review. Only boot tested. Thanks.
Comment 6 Fedora Update System 2008-12-17 11:21:13 EST
kernel-2.6.27.9-159.fc10 has been submitted as an update for Fedora 10.
http://admin.fedoraproject.org/updates/kernel-2.6.27.9-159.fc10
Comment 7 Fedora Update System 2008-12-17 11:22:12 EST
kernel-2.6.27.9-73.fc9 has been submitted as an update for Fedora 9.
http://admin.fedoraproject.org/updates/kernel-2.6.27.9-73.fc9
Comment 8 Fedora Update System 2008-12-24 13:45:23 EST
kernel-2.6.27.9-159.fc10 has been pushed to the Fedora 10 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 9 Fedora Update System 2008-12-24 13:47:39 EST
kernel-2.6.27.9-73.fc9 has been pushed to the Fedora 9 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 11 Fedora Update System 2009-01-07 04:17:45 EST
kernel-2.6.26.8-57.fc8 has been pushed to the Fedora 8 stable repository.  If problems still persist, please make note of it in this bug report.
Comment 14 Vincent Danen 2010-12-21 12:53:01 EST
This was addressed via:

Red Hat Enterprise Linux (v. 5.2.z server) (RHSA-2009:0021)
MRG Realtime for RHEL 5 Server (RHSA-2009:0053)
Red Hat Enterprise Linux version 5 (RHSA-2009:0225)