[PATCH 3.9 and earlier] hpfs: deadlock and race in directory lseek()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

This is backport of patch 31abdab9c11bb1694ecd1476a7edbe8e964d94ac for 
stable kernels 3.9 and earlier.

Mikulas


commit 31abdab9c11bb1694ecd1476a7edbe8e964d94ac
Author: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Date:   Sat May 18 02:38:52 2013 -0400

    hpfs: deadlock and race in directory lseek()

    For one thing, there's an ABBA deadlock on hpfs fs-wide lock and i_mutex
    in hpfs_dir_lseek() - there's a lot of methods that grab the former with
    the caller already holding the latter, so it must take i_mutex first.

    For another, locking the damn thing, carefully validating the offset,
    then dropping locks and assigning the offset is obviously racy.

    Moreover, we _must_ do hpfs_add_pos(), or the machinery in dnode.c
    won't modify the sucker on B-tree surgeries.

    Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>


---
 fs/hpfs/dir.c  |   10 ++++++----
 fs/hpfs/file.c |   36 ++++++++++++++++++++----------------
 2 files changed, 26 insertions(+), 20 deletions(-)

Index: linux-stable/fs/hpfs/dir.c
===================================================================
--- linux-stable.orig/fs/hpfs/dir.c	2014-02-10 23:11:51.000000000 +0100
+++ linux-stable/fs/hpfs/dir.c	2014-02-10 23:14:53.000000000 +0100
@@ -33,25 +33,27 @@ static loff_t hpfs_dir_lseek(struct file
 	if (whence == SEEK_DATA || whence == SEEK_HOLE)
 		return -EINVAL;
 
+	mutex_lock(&i->i_mutex);
 	hpfs_lock(s);
 
 	/*printk("dir lseek\n");*/
 	if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
-	mutex_lock(&i->i_mutex);
 	pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
 	while (pos != new_off) {
 		if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
 		else goto fail;
 		if (pos == 12) goto fail;
 	}
-	mutex_unlock(&i->i_mutex);
+	hpfs_add_pos(i, &filp->f_pos);
 ok:
+	filp->f_pos = new_off;
 	hpfs_unlock(s);
-	return filp->f_pos = new_off;
-fail:
 	mutex_unlock(&i->i_mutex);
+	return new_off;
+fail:
 	/*printk("illegal lseek: %016llx\n", new_off);*/
 	hpfs_unlock(s);
+	mutex_unlock(&i->i_mutex);
 	return -ESPIPE;
 }
 
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]