Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 446931543982 ("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>

authored by

Yun Zhou and committed by
Yu Kuai
0dc76205 cc394b94

+13 -9
+6 -8
drivers/md/md.c
··· 99 99 struct md_rdev *this); 100 100 static void mddev_detach(struct mddev *mddev); 101 101 static void export_rdev(struct md_rdev *rdev, struct mddev *mddev); 102 - static void md_wakeup_thread_directly(struct md_thread __rcu *thread); 102 + static void md_wakeup_thread_directly(struct md_thread __rcu **thread); 103 103 104 104 /* 105 105 * Default number of read corrections we'll attempt on an rdev ··· 5136 5136 * Thread might be blocked waiting for metadata update which will now 5137 5137 * never happen 5138 5138 */ 5139 - md_wakeup_thread_directly(mddev->sync_thread); 5139 + md_wakeup_thread_directly(&mddev->sync_thread); 5140 5140 if (work_pending(&mddev->sync_work)) 5141 5141 flush_work(&mddev->sync_work); 5142 5142 ··· 8375 8375 return 0; 8376 8376 } 8377 8377 8378 - static void md_wakeup_thread_directly(struct md_thread __rcu *thread) 8378 + static void md_wakeup_thread_directly(struct md_thread __rcu **thread) 8379 8379 { 8380 8380 struct md_thread *t; 8381 8381 8382 8382 rcu_read_lock(); 8383 - t = rcu_dereference(thread); 8383 + t = rcu_dereference(*thread); 8384 8384 if (t) 8385 8385 wake_up_process(t->tsk); 8386 8386 rcu_read_unlock(); 8387 8387 } 8388 8388 8389 - void md_wakeup_thread(struct md_thread __rcu *thread) 8389 + void __md_wakeup_thread(struct md_thread __rcu *thread) 8390 8390 { 8391 8391 struct md_thread *t; 8392 8392 8393 - rcu_read_lock(); 8394 8393 t = rcu_dereference(thread); 8395 8394 if (t) { 8396 8395 pr_debug("md: waking up MD thread %s.\n", t->tsk->comm); ··· 8397 8398 if (wq_has_sleeper(&t->wqueue)) 8398 8399 wake_up(&t->wqueue); 8399 8400 } 8400 - rcu_read_unlock(); 8401 8401 } 8402 - EXPORT_SYMBOL(md_wakeup_thread); 8402 + EXPORT_SYMBOL(__md_wakeup_thread); 8403 8403 8404 8404 struct md_thread *md_register_thread(void (*run) (struct md_thread *), 8405 8405 struct mddev *mddev, const char *name)
+7 -1
drivers/md/md.h
··· 882 882 883 883 #define THREAD_WAKEUP 0 884 884 885 + #define md_wakeup_thread(thread) do { \ 886 + rcu_read_lock(); \ 887 + __md_wakeup_thread(thread); \ 888 + rcu_read_unlock(); \ 889 + } while (0) 890 + 885 891 static inline void safe_put_page(struct page *p) 886 892 { 887 893 if (p) put_page(p); ··· 901 895 struct mddev *mddev, 902 896 const char *name); 903 897 extern void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp); 904 - extern void md_wakeup_thread(struct md_thread __rcu *thread); 898 + extern void __md_wakeup_thread(struct md_thread __rcu *thread); 905 899 extern void md_check_recovery(struct mddev *mddev); 906 900 extern void md_reap_sync_thread(struct mddev *mddev); 907 901 extern enum sync_action md_sync_action(struct mddev *mddev);