[PATCH OLK-6.6] mm: fix double initialization race in mm_counter_try_switch_to_pcpu
hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9960 ---------------------------------------- When CONFIG_MM_COUNTER_ATOMIC is enabled, mm counters start in atomic mode (using count_atomic) for single-threaded processes and switch to percpu mode (using count) upon the first CLONE_THREAD. The switch is performed by mm_counter_try_switch_to_pcpu(), which calls percpu_counter_switch_to_pcpu_many() without any lock protection. If the first switch attempt fails (GFP_ATOMIC allocation failure under memory pressure), the mm remains in atomic mode while the process is now multi-threaded. Subsequent CLONE_THREAD calls from two threads can race into mm_counter_try_switch_to_pcpu() simultaneously: Thread A (CLONE_THREAD) Thread B (CLONE_THREAD) ------------------------- ------------------------- percpu_counter_switch_to_pcpu_many percpu_counter_switch_to_pcpu_many percpu_counter_initialized? false percpu_counter_initialized? false __percpu_counter_init_many __percpu_counter_init_many alloc counters (1st) alloc counters (2nd, leaked) fbc[i].counters = ptr1 fbc[i].counters = ptr2 (overwrite) list_add(&fbc[i].list) list_add(&fbc[i].list) (double add) Both threads pass the percpu_counter_initialized() check before either completes __percpu_counter_init_many(), leading to: - Double percpu memory allocation (first allocation leaked) - Concurrent re-init of fbc[i].lock - Same fbc[i].list node added twice to the global percpu_counters list, corrupting the list and potentially triggering a list_add BUG() Fix this by serializing the switch with mm->arg_lock. This ensures the check-then-init sequence in percpu_counter_switch_to_pcpu_many() is atomic across concurrent CLONE_THREAD callers: if the first caller succeeds, the second observes counters != NULL and returns early; if the first fails, the second retries safely without overlap. Fixes: 46213033b804 ("mm: add config option for atomic mode in mm counter") Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- include/linux/mm.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 5fc9092ea039..dd84843c3029 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2793,10 +2793,16 @@ static inline s64 get_mm_counter_sum(struct mm_struct *mm, int member) static inline int mm_counter_try_switch_to_pcpu(struct mm_struct *mm) { + int ret; + if (!mm_counter_is_atomic()) return 0; - return percpu_counter_switch_to_pcpu_many(mm->rss_stat, NR_MM_COUNTERS); + spin_lock(&mm->arg_lock); + ret = percpu_counter_switch_to_pcpu_many(mm->rss_stat, NR_MM_COUNTERS); + spin_unlock(&mm->arg_lock); + + return ret; } static inline int mm_counter_init(struct mm_struct *mm) -- 2.43.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/27625 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/RZF... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/27625 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/RZF...
participants (2)
-
Jinjiang Tu -
patchwork bot