mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
md: protect md_thread with rcu
Currently, there are many places that md_thread can be accessed without protection, following are known scenarios that can cause null-ptr-dereference or uaf: 1) sync_thread that is allocated and started from md_start_sync() 2) mddev->thread can be accessed directly from timeout_store() and md_bitmap_daemon_work() 3) md_unregister_thread() from action_store(). Currently, a global spinlock 'pers_lock' is borrowed to protect 'mddev->thread' in some places, this problem can be fixed likewise, however, use a global lock for all the cases is not good. Fix this problem by protecting all md_thread with rcu. Signed-off-by: Yu Kuai <yukuai3@huawei.com> Signed-off-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/r/20230523021017.3048783-6-yukuai1@huaweicloud.com
This commit is contained in:
@@ -120,7 +120,7 @@ struct r5l_log {
|
||||
struct bio_set bs;
|
||||
mempool_t meta_pool;
|
||||
|
||||
struct md_thread *reclaim_thread;
|
||||
struct md_thread __rcu *reclaim_thread;
|
||||
unsigned long reclaim_target; /* number of space that need to be
|
||||
* reclaimed. if it's 0, reclaim spaces
|
||||
* used by io_units which are in
|
||||
@@ -1576,17 +1576,18 @@ void r5l_wake_reclaim(struct r5l_log *log, sector_t space)
|
||||
|
||||
void r5l_quiesce(struct r5l_log *log, int quiesce)
|
||||
{
|
||||
struct mddev *mddev;
|
||||
struct mddev *mddev = log->rdev->mddev;
|
||||
struct md_thread *thread = rcu_dereference_protected(
|
||||
log->reclaim_thread, lockdep_is_held(&mddev->reconfig_mutex));
|
||||
|
||||
if (quiesce) {
|
||||
/* make sure r5l_write_super_and_discard_space exits */
|
||||
mddev = log->rdev->mddev;
|
||||
wake_up(&mddev->sb_wait);
|
||||
kthread_park(log->reclaim_thread->tsk);
|
||||
kthread_park(thread->tsk);
|
||||
r5l_wake_reclaim(log, MaxSector);
|
||||
r5l_do_reclaim(log);
|
||||
} else
|
||||
kthread_unpark(log->reclaim_thread->tsk);
|
||||
kthread_unpark(thread->tsk);
|
||||
}
|
||||
|
||||
bool r5l_log_disk_error(struct r5conf *conf)
|
||||
@@ -3063,6 +3064,7 @@ void r5c_update_on_rdev_error(struct mddev *mddev, struct md_rdev *rdev)
|
||||
int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
|
||||
{
|
||||
struct r5l_log *log;
|
||||
struct md_thread *thread;
|
||||
int ret;
|
||||
|
||||
pr_debug("md/raid:%s: using device %pg as journal\n",
|
||||
@@ -3121,11 +3123,13 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
|
||||
spin_lock_init(&log->tree_lock);
|
||||
INIT_RADIX_TREE(&log->big_stripe_tree, GFP_NOWAIT | __GFP_NOWARN);
|
||||
|
||||
log->reclaim_thread = md_register_thread(r5l_reclaim_thread,
|
||||
log->rdev->mddev, "reclaim");
|
||||
if (!log->reclaim_thread)
|
||||
thread = md_register_thread(r5l_reclaim_thread, log->rdev->mddev,
|
||||
"reclaim");
|
||||
if (!thread)
|
||||
goto reclaim_thread;
|
||||
log->reclaim_thread->timeout = R5C_RECLAIM_WAKEUP_INTERVAL;
|
||||
|
||||
thread->timeout = R5C_RECLAIM_WAKEUP_INTERVAL;
|
||||
rcu_assign_pointer(log->reclaim_thread, thread);
|
||||
|
||||
init_waitqueue_head(&log->iounit_wait);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user