Home Home > GIT Browse
summaryrefslogtreecommitdiff
authorAl Viro <viro@zeniv.linux.org.uk>2008-05-06 17:58:34 (GMT)
committer Greg Kroah-Hartman <gregkh@suse.de>2008-05-06 23:21:10 (GMT)
commitc493a1dd8b3a93b57208319a77a8238f76dabca2 (patch) (unidiff)
treef21c54225f9ce7b1954041463470263bd043316e
parent1420f09c0b8a88f9df2034e6ba04fcc4c3f6925e (diff)
fix SMP ordering hole in fcntl_setlk() (CVE-2008-1669)
commit 0b2bac2f1ea0d33a3621b27ca68b9ae760fca2e9 upstream. fcntl_setlk()/close() race prevention has a subtle hole - we need to make sure that if we *do* have an fcntl/close race on SMP box, the access to descriptor table and inode->i_flock won't get reordered. As it is, we get STORE inode->i_flock, LOAD descriptor table entry vs. STORE descriptor table entry, LOAD inode->i_flock with not a single lock in common on both sides. We do have BKL around the first STORE, but check in locks_remove_posix() is outside of BKL and for a good reason - we don't want BKL on common path of close(2). Solution is to hold ->file_lock around fcheck() in there; that orders us wrt removal from descriptor table that preceded locks_remove_posix() on close path and we either come first (in which case eviction will be handled by the close side) or we'll see the effect of close and do eviction ourselves. Note that even though it's read-only access, we do need ->file_lock here - rcu_read_lock() won't be enough to order the things. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--fs/locks.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 43c0af2..159e0f6 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1750,6 +1750,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
1750 struct file_lock *file_lock = locks_alloc_lock(); 1750 struct file_lock *file_lock = locks_alloc_lock();
1751 struct flock flock; 1751 struct flock flock;
1752 struct inode *inode; 1752 struct inode *inode;
1753 struct file *f;
1753 int error; 1754 int error;
1754 1755
1755 if (file_lock == NULL) 1756 if (file_lock == NULL)
@@ -1822,7 +1823,15 @@ again:
1822 * Attempt to detect a close/fcntl race and recover by 1823 * Attempt to detect a close/fcntl race and recover by
1823 * releasing the lock that was just acquired. 1824 * releasing the lock that was just acquired.
1824 */ 1825 */
1825 if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { 1826 /*
1827 * we need that spin_lock here - it prevents reordering between
1828 * update of inode->i_flock and check for it done in close().
1829 * rcu_read_lock() wouldn't do.
1830 */
1831 spin_lock(&current->files->file_lock);
1832 f = fcheck(fd);
1833 spin_unlock(&current->files->file_lock);
1834 if (!error && f != filp && flock.l_type != F_UNLCK) {
1826 flock.l_type = F_UNLCK; 1835 flock.l_type = F_UNLCK;
1827 goto again; 1836 goto again;
1828 } 1837 }
@@ -1878,6 +1887,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
1878 struct file_lock *file_lock = locks_alloc_lock(); 1887 struct file_lock *file_lock = locks_alloc_lock();
1879 struct flock64 flock; 1888 struct flock64 flock;
1880 struct inode *inode; 1889 struct inode *inode;
1890 struct file *f;
1881 int error; 1891 int error;
1882 1892
1883 if (file_lock == NULL) 1893 if (file_lock == NULL)
@@ -1950,7 +1960,10 @@ again:
1950 * Attempt to detect a close/fcntl race and recover by 1960 * Attempt to detect a close/fcntl race and recover by
1951 * releasing the lock that was just acquired. 1961 * releasing the lock that was just acquired.
1952 */ 1962 */
1953 if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { 1963 spin_lock(&current->files->file_lock);
1964 f = fcheck(fd);
1965 spin_unlock(&current->files->file_lock);
1966 if (!error && f != filp && flock.l_type != F_UNLCK) {
1954 flock.l_type = F_UNLCK; 1967 flock.l_type = F_UNLCK;
1955 goto again; 1968 goto again;
1956 } 1969 }