Skip to content

Commit 33ec3e5

Browse files
jankaraaxboe
authored andcommitted
loop: Don't change loop device under exclusive opener
Loop module allows calling LOOP_SET_FD while there are other openers of the loop device. Even exclusive ones. This can lead to weird consequences such as kernel deadlocks like: mount_bdev() lo_ioctl() udf_fill_super() udf_load_vrs() sb_set_blocksize() - sets desired block size B udf_tread() sb_bread() __bread_gfp(bdev, block, B) loop_set_fd() set_blocksize() - now __getblk_slow() indefinitely loops because B != bdev block size Fix the problem by disallowing LOOP_SET_FD ioctl when there are exclusive openers of a loop device. [Deliberately chosen not to CC stable as a user with priviledges to trigger this race has other means of taking the system down and this has a potential of breaking some weird userspace setup] Reported-and-tested-by: [email protected] Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent a278682 commit 33ec3e5

File tree

1 file changed

+17
-1
lines changed

1 file changed

+17
-1
lines changed

drivers/block/loop.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,9 +945,20 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
945945
if (!file)
946946
goto out;
947947

948+
/*
949+
* If we don't hold exclusive handle for the device, upgrade to it
950+
* here to avoid changing device under exclusive owner.
951+
*/
952+
if (!(mode & FMODE_EXCL)) {
953+
bdgrab(bdev);
954+
error = blkdev_get(bdev, mode | FMODE_EXCL, loop_set_fd);
955+
if (error)
956+
goto out_putf;
957+
}
958+
948959
error = mutex_lock_killable(&loop_ctl_mutex);
949960
if (error)
950-
goto out_putf;
961+
goto out_bdev;
951962

952963
error = -EBUSY;
953964
if (lo->lo_state != Lo_unbound)
@@ -1012,10 +1023,15 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
10121023
mutex_unlock(&loop_ctl_mutex);
10131024
if (partscan)
10141025
loop_reread_partitions(lo, bdev);
1026+
if (!(mode & FMODE_EXCL))
1027+
blkdev_put(bdev, mode | FMODE_EXCL);
10151028
return 0;
10161029

10171030
out_unlock:
10181031
mutex_unlock(&loop_ctl_mutex);
1032+
out_bdev:
1033+
if (!(mode & FMODE_EXCL))
1034+
blkdev_put(bdev, mode | FMODE_EXCL);
10191035
out_putf:
10201036
fput(file);
10211037
out:

0 commit comments

Comments
 (0)