mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 08:33:17 +02:00
md: fix rcu protection in md_wakeup_thread
We attempted to use RCU to protect the pointer 'thread', but directly
passed the value when calling md_wakeup_thread(). This means that the
RCU pointer has been acquired before rcu_read_lock(), which renders
rcu_read_lock() ineffective and could lead to a use-after-free.
Link: https://lore.kernel.org/linux-raid/20251015083227.1079009-1-yun.zhou@windriver.com
Fixes: 4469315439 ("md: protect md_thread with rcu")
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Reviewed-by: Li Nan <linan122@huawei.com>
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
This commit is contained in:
parent
cc394b94dc
commit
0dc7620554
|
|
@ -99,7 +99,7 @@ static int remove_and_add_spares(struct mddev *mddev,
|
|||
struct md_rdev *this);
|
||||
static void mddev_detach(struct mddev *mddev);
|
||||
static void export_rdev(struct md_rdev *rdev, struct mddev *mddev);
|
||||
static void md_wakeup_thread_directly(struct md_thread __rcu *thread);
|
||||
static void md_wakeup_thread_directly(struct md_thread __rcu **thread);
|
||||
|
||||
/*
|
||||
* Default number of read corrections we'll attempt on an rdev
|
||||
|
|
@ -5136,7 +5136,7 @@ static void stop_sync_thread(struct mddev *mddev, bool locked)
|
|||
* Thread might be blocked waiting for metadata update which will now
|
||||
* never happen
|
||||
*/
|
||||
md_wakeup_thread_directly(mddev->sync_thread);
|
||||
md_wakeup_thread_directly(&mddev->sync_thread);
|
||||
if (work_pending(&mddev->sync_work))
|
||||
flush_work(&mddev->sync_work);
|
||||
|
||||
|
|
@ -8375,22 +8375,21 @@ static int md_thread(void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void md_wakeup_thread_directly(struct md_thread __rcu *thread)
|
||||
static void md_wakeup_thread_directly(struct md_thread __rcu **thread)
|
||||
{
|
||||
struct md_thread *t;
|
||||
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(thread);
|
||||
t = rcu_dereference(*thread);
|
||||
if (t)
|
||||
wake_up_process(t->tsk);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void md_wakeup_thread(struct md_thread __rcu *thread)
|
||||
void __md_wakeup_thread(struct md_thread __rcu *thread)
|
||||
{
|
||||
struct md_thread *t;
|
||||
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(thread);
|
||||
if (t) {
|
||||
pr_debug("md: waking up MD thread %s.\n", t->tsk->comm);
|
||||
|
|
@ -8398,9 +8397,8 @@ void md_wakeup_thread(struct md_thread __rcu *thread)
|
|||
if (wq_has_sleeper(&t->wqueue))
|
||||
wake_up(&t->wqueue);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(md_wakeup_thread);
|
||||
EXPORT_SYMBOL(__md_wakeup_thread);
|
||||
|
||||
struct md_thread *md_register_thread(void (*run) (struct md_thread *),
|
||||
struct mddev *mddev, const char *name)
|
||||
|
|
|
|||
|
|
@ -882,6 +882,12 @@ struct md_io_clone {
|
|||
|
||||
#define THREAD_WAKEUP 0
|
||||
|
||||
#define md_wakeup_thread(thread) do { \
|
||||
rcu_read_lock(); \
|
||||
__md_wakeup_thread(thread); \
|
||||
rcu_read_unlock(); \
|
||||
} while (0)
|
||||
|
||||
static inline void safe_put_page(struct page *p)
|
||||
{
|
||||
if (p) put_page(p);
|
||||
|
|
@ -895,7 +901,7 @@ extern struct md_thread *md_register_thread(
|
|||
struct mddev *mddev,
|
||||
const char *name);
|
||||
extern void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp);
|
||||
extern void md_wakeup_thread(struct md_thread __rcu *thread);
|
||||
extern void __md_wakeup_thread(struct md_thread __rcu *thread);
|
||||
extern void md_check_recovery(struct mddev *mddev);
|
||||
extern void md_reap_sync_thread(struct mddev *mddev);
|
||||
extern enum sync_action md_sync_action(struct mddev *mddev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user