Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=85c59580b30c82aa771aa33b37217a6b6851bc14
Commit:     85c59580b30c82aa771aa33b37217a6b6851bc14
Parent:     f0c1cd0eaf0b127356c2c09e40305453bc361b0f
Author:     Pavel Emelyanov <[EMAIL PROTECTED]>
AuthorDate: Thu Sep 20 12:45:02 2007 +0400
Committer:  J. Bruce Fields <[EMAIL PROTECTED]>
CommitDate: Tue Oct 9 18:32:45 2007 -0400

    locks: Fix potential OOPS in generic_setlease()
    
    This code is run under lock_kernel(), which is dropped during
    sleeping operations, so the following race is possible:
    
    CPU1:                                CPU2:
      vfs_setlease();                    vfs_setlease();
      lock_kernel();
                                         lock_kernel(); /* spin */
      generic_setlease():
        ...
        for (before = ...)
        /* here we found some lease after
         * which we will insert the new one
         */
        fl = locks_alloc_lock();
        /* go to sleep in this allocation and
         * drop the BKL
         */
                                         generic_setlease():
                                           ...
                                           for (before = ...)
                                           /* here we find the "before" pointing
                                            * at the one we found on CPU1
                                            */
                                          ->fl_change(my_before, arg);
                                                  lease_modify();
                                                         locks_free_lock();
                                                         /* and we freed it */
                                         ...
                                         unlock_kernel();
       locks_insert_lock(before, fl);
       /* OOPS! We have just tried to add the lease
        * at the tail of already removed one
        */
    
    The similar races are already handled in other code - all the
    allocations are performed before any checks/updates.
    
    Thanks to Kamalesh Babulal for testing and for a bug report on an
    earlier version.
    
    Signed-off-by: Pavel Emelyanov <[EMAIL PROTECTED]>
    Signed-off-by: J. Bruce Fields <[EMAIL PROTECTED]>
    Cc: Kamalesh Babulal <[EMAIL PROTECTED]>
---
 fs/locks.c |   21 ++++++++++++---------
 1 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 282b6c1..43dbc7f 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1343,6 +1343,7 @@ int fcntl_getlease(struct file *filp)
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
+       struct file_lock *new_fl = NULL;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        int error, rdlease_count = 0, wrlease_count = 0;
@@ -1369,6 +1370,11 @@ int generic_setlease(struct file *filp, long arg, struct 
file_lock **flp)
                || (atomic_read(&inode->i_count) > 1)))
                goto out;
 
+       error = -ENOMEM;
+       new_fl = locks_alloc_lock();
+       if (new_fl == NULL)
+               goto out;
+
        /*
         * At this point, we know that if there is an exclusive
         * lease on this file, then we hold it on this filp
@@ -1411,18 +1417,15 @@ int generic_setlease(struct file *filp, long arg, 
struct file_lock **flp)
        if (!leases_enable)
                goto out;
 
-       error = -ENOMEM;
-       fl = locks_alloc_lock();
-       if (fl == NULL)
-               goto out;
-
-       locks_copy_lock(fl, lease);
+       locks_copy_lock(new_fl, lease);
+       locks_insert_lock(before, new_fl);
 
-       locks_insert_lock(before, fl);
+       *flp = new_fl;
+       return 0;
 
-       *flp = fl;
-       error = 0;
 out:
+       if (new_fl != NULL)
+               locks_free_lock(new_fl);
        return error;
 }
 EXPORT_SYMBOL(generic_setlease);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to