Skip to content

Commit 1c500ad

Browse files
Tetsuo Handaaxboe
Tetsuo Handa
authored andcommitted
loop: reduce the loop_ctl_mutex scope
syzbot is reporting circular locking problem at __loop_clr_fd() [1], for commit a160c61 ("block: add an optional probe callback to major_names") is calling the module's probe function with major_names_lock held. Fortunately, since commit 990e781 ("block: loop: fix deadlock between open and remove") stopped holding loop_ctl_mutex in lo_open(), current role of loop_ctl_mutex is to serialize access to loop_index_idr and loop_add()/loop_remove(); in other words, management of id for IDR. To avoid holding loop_ctl_mutex during whole add/remove operation, use a bool flag to indicate whether the loop device is ready for use. loop_unregister_transfer() which is called from cleanup_cryptoloop() currently has possibility of use-after-free problem due to lack of serialization between kfree() from loop_remove() from loop_control_remove() and mutex_lock() from unregister_transfer_cb(). But since lo->lo_encryption should be already NULL when this function is called due to module unload, and commit 222013f ("cryptoloop: add a deprecation warning") indicates that we will remove this function shortly, this patch updates this function to emit warning instead of checking lo->lo_encryption. Holding loop_ctl_mutex in loop_exit() is pointless, for all users must close /dev/loop-control and /dev/loop$num (in order to drop module's refcount to 0) before loop_exit() starts, and nobody can open /dev/loop-control or /dev/loop$num afterwards. Link: https://syzkaller.appspot.com/bug?id=7bb10e8b62f83e4d445cdf4c13d69e407e629558 [1] Reported-by: syzbot <[email protected]> Signed-off-by: Tetsuo Handa <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 0ef47db commit 1c500ad

File tree

2 files changed

+50
-26
lines changed

2 files changed

+50
-26
lines changed

drivers/block/loop.c

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,28 +2111,27 @@ int loop_register_transfer(struct loop_func_table *funcs)
21112111
return 0;
21122112
}
21132113

2114-
static int unregister_transfer_cb(int id, void *ptr, void *data)
2115-
{
2116-
struct loop_device *lo = ptr;
2117-
struct loop_func_table *xfer = data;
2118-
2119-
mutex_lock(&lo->lo_mutex);
2120-
if (lo->lo_encryption == xfer)
2121-
loop_release_xfer(lo);
2122-
mutex_unlock(&lo->lo_mutex);
2123-
return 0;
2124-
}
2125-
21262114
int loop_unregister_transfer(int number)
21272115
{
21282116
unsigned int n = number;
21292117
struct loop_func_table *xfer;
21302118

21312119
if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
21322120
return -EINVAL;
2121+
/*
2122+
* This function is called from only cleanup_cryptoloop().
2123+
* Given that each loop device that has a transfer enabled holds a
2124+
* reference to the module implementing it we should never get here
2125+
* with a transfer that is set (unless forced module unloading is
2126+
* requested). Thus, check module's refcount and warn if this is
2127+
* not a clean unloading.
2128+
*/
2129+
#ifdef CONFIG_MODULE_UNLOAD
2130+
if (xfer->owner && module_refcount(xfer->owner) != -1)
2131+
pr_err("Danger! Unregistering an in use transfer function.\n");
2132+
#endif
21332133

21342134
xfer_funcs[n] = NULL;
2135-
idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer);
21362135
return 0;
21372136
}
21382137

@@ -2323,8 +2322,9 @@ static int loop_add(int i)
23232322
} else {
23242323
err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
23252324
}
2325+
mutex_unlock(&loop_ctl_mutex);
23262326
if (err < 0)
2327-
goto out_unlock;
2327+
goto out_free_dev;
23282328
i = err;
23292329

23302330
err = -ENOMEM;
@@ -2393,15 +2393,19 @@ static int loop_add(int i)
23932393
disk->events = DISK_EVENT_MEDIA_CHANGE;
23942394
disk->event_flags = DISK_EVENT_FLAG_UEVENT;
23952395
sprintf(disk->disk_name, "loop%d", i);
2396+
/* Make this loop device reachable from pathname. */
23962397
add_disk(disk);
2398+
/* Show this loop device. */
2399+
mutex_lock(&loop_ctl_mutex);
2400+
lo->idr_visible = true;
23972401
mutex_unlock(&loop_ctl_mutex);
23982402
return i;
23992403

24002404
out_cleanup_tags:
24012405
blk_mq_free_tag_set(&lo->tag_set);
24022406
out_free_idr:
2407+
mutex_lock(&loop_ctl_mutex);
24032408
idr_remove(&loop_index_idr, i);
2404-
out_unlock:
24052409
mutex_unlock(&loop_ctl_mutex);
24062410
out_free_dev:
24072411
kfree(lo);
@@ -2411,9 +2415,14 @@ static int loop_add(int i)
24112415

24122416
static void loop_remove(struct loop_device *lo)
24132417
{
2418+
/* Make this loop device unreachable from pathname. */
24142419
del_gendisk(lo->lo_disk);
24152420
blk_cleanup_disk(lo->lo_disk);
24162421
blk_mq_free_tag_set(&lo->tag_set);
2422+
mutex_lock(&loop_ctl_mutex);
2423+
idr_remove(&loop_index_idr, lo->lo_number);
2424+
mutex_unlock(&loop_ctl_mutex);
2425+
/* There is no route which can find this loop device. */
24172426
mutex_destroy(&lo->lo_mutex);
24182427
kfree(lo);
24192428
}
@@ -2437,31 +2446,40 @@ static int loop_control_remove(int idx)
24372446
return -EINVAL;
24382447
}
24392448

2449+
/* Hide this loop device for serialization. */
24402450
ret = mutex_lock_killable(&loop_ctl_mutex);
24412451
if (ret)
24422452
return ret;
2443-
24442453
lo = idr_find(&loop_index_idr, idx);
2445-
if (!lo) {
2454+
if (!lo || !lo->idr_visible)
24462455
ret = -ENODEV;
2447-
goto out_unlock_ctrl;
2448-
}
2456+
else
2457+
lo->idr_visible = false;
2458+
mutex_unlock(&loop_ctl_mutex);
2459+
if (ret)
2460+
return ret;
24492461

2462+
/* Check whether this loop device can be removed. */
24502463
ret = mutex_lock_killable(&lo->lo_mutex);
24512464
if (ret)
2452-
goto out_unlock_ctrl;
2465+
goto mark_visible;
24532466
if (lo->lo_state != Lo_unbound ||
24542467
atomic_read(&lo->lo_refcnt) > 0) {
24552468
mutex_unlock(&lo->lo_mutex);
24562469
ret = -EBUSY;
2457-
goto out_unlock_ctrl;
2470+
goto mark_visible;
24582471
}
2472+
/* Mark this loop device no longer open()-able. */
24592473
lo->lo_state = Lo_deleting;
24602474
mutex_unlock(&lo->lo_mutex);
24612475

2462-
idr_remove(&loop_index_idr, lo->lo_number);
24632476
loop_remove(lo);
2464-
out_unlock_ctrl:
2477+
return 0;
2478+
2479+
mark_visible:
2480+
/* Show this loop device again. */
2481+
mutex_lock(&loop_ctl_mutex);
2482+
lo->idr_visible = true;
24652483
mutex_unlock(&loop_ctl_mutex);
24662484
return ret;
24672485
}
@@ -2475,7 +2493,8 @@ static int loop_control_get_free(int idx)
24752493
if (ret)
24762494
return ret;
24772495
idr_for_each_entry(&loop_index_idr, lo, id) {
2478-
if (lo->lo_state == Lo_unbound)
2496+
/* Hitting a race results in creating a new loop device which is harmless. */
2497+
if (lo->idr_visible && data_race(lo->lo_state) == Lo_unbound)
24792498
goto found;
24802499
}
24812500
mutex_unlock(&loop_ctl_mutex);
@@ -2591,10 +2610,14 @@ static void __exit loop_exit(void)
25912610
unregister_blkdev(LOOP_MAJOR, "loop");
25922611
misc_deregister(&loop_misc);
25932612

2594-
mutex_lock(&loop_ctl_mutex);
2613+
/*
2614+
* There is no need to use loop_ctl_mutex here, for nobody else can
2615+
* access loop_index_idr when this module is unloading (unless forced
2616+
* module unloading is requested). If this is not a clean unloading,
2617+
* we have no means to avoid kernel crash.
2618+
*/
25952619
idr_for_each_entry(&loop_index_idr, lo, id)
25962620
loop_remove(lo);
2597-
mutex_unlock(&loop_ctl_mutex);
25982621

25992622
idr_destroy(&loop_index_idr);
26002623
}

drivers/block/loop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ struct loop_device {
6868
struct blk_mq_tag_set tag_set;
6969
struct gendisk *lo_disk;
7070
struct mutex lo_mutex;
71+
bool idr_visible;
7172
};
7273

7374
struct loop_cmd {

0 commit comments

Comments
 (0)