FAILED: patch "[PATCH] sched/core: Fix use-after-free bug in dup_user_cpus_ptr()" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
87ca4f9efbd7 ("sched/core: Fix use-after-free bug in dup_user_cpus_ptr()") 8f9ea86fdf99 ("sched: Always preserve the user requested cpumask") 713a2e21a513 ("sched: Introduce affinity_context")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 87ca4f9efbd7cc649ff43b87970888f2812945b8 Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug in dup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Since commit 07ec77a1d4e8 ("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing of user_cpus_ptr are done under pi_lock for arm64 architecture. However, dup_user_cpus_ptr() accesses user_cpus_ptr without any lock protection. Since sched_setaffinity() can be invoked from another process, the process being modified may be undergoing fork() at the same time. When racing with the clearing of user_cpus_ptr in __set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.
Commit 8f9ea86fdf99 ("sched: Always preserve the user requested cpumask") fixes this problem as user_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit 851a723e45d1 ("sched: Always clear user_cpus_ptr in do_set_cpus_allowed()") which allows the clearing of user_cpus_ptr in do_set_cpus_allowed(). This time, it will affect all arches.
Fix this bug by always clearing the user_cpus_ptr of the newly cloned/forked task before the copying process starts and check the user_cpus_ptr state of the source task under pi_lock.
Note to stable, this patch won't be applicable to stable releases. Just copy the new dup_user_cpus_ptr() function over.
kernel/sched/core.c +29 -5
@@ -2612,19 +2612,43 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)int dup_user_cpus_ptr (struct task_struct *dst,struct task_struct *src,int node) { +cpumask_t *user_mask;unsigned long flags; -if (!src->user_cpus_ptr) +/* +* Always clear dst->user_cpus_ptr first as their user_cpus_ptr's +* may differ by now due to racing. +*/ + dst->user_cpus_ptr =NULL ; + +/* +* This check is racy and losing the race is a valid situation. +* It is not worth the extra overhead of taking the pi_lock on +* every fork/clone. +*/ +if (data_race (!src->user_cpus_ptr))return 0 ; - dst->user_cpus_ptr =kmalloc_node (cpumask_size (),GFP_KERNEL , node); -if (!dst->user_cpus_ptr) + user_mask =kmalloc_node (cpumask_size (),GFP_KERNEL , node); +if (!user_mask)return -ENOMEM ; -/* Use pi_lock to protect content of user_cpus_ptr */ +/* +* Use pi_lock to protect content of user_cpus_ptr +* +* Though unlikely, user_cpus_ptr can be reset to NULL by a concurrent +* do_set_cpus_allowed(). +*/ raw_spin_lock_irqsave (&src->pi_lock, flags); -cpumask_copy (dst->user_cpus_ptr, src->user_cpus_ptr); +if (src->user_cpus_ptr) { +swap (dst->user_cpus_ptr, user_mask); +cpumask_copy (dst->user_cpus_ptr, src->user_cpus_ptr); + }raw_spin_unlock_irqrestore (&src->pi_lock, flags); + +if (unlikely (user_mask)) +kfree (user_mask); +return 0 ; }
Quoted 42 lines · On 1/14/23 04:53, [email protected] wrote:
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Possible dependencies:
87ca4f9efbd7("sched/core: Fix use-after-free bug indup_user_cpus_ptr()")8f9ea86fdf99("sched: Always preserve the user requested cpumask")713a2e21a513("sched: Introduceaffinity_context")thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
87ca4f9efbd7cc649ff43b87970888f2812945b8Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug indup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitSince commit
07ec77a1d4e8("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing ofuser_cpus_ptrare done underpi_lockfor arm64 architecture. However,dup_user_cpus_ptr()accessesuser_cpus_ptrwithout any lock protection. Sincesched_setaffinity()can be invoked from another process, the process being modified may be undergoingfork()at the same time. When racing with the clearing ofuser_cpus_ptrin__set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.Commit
8f9ea86fdf99("sched: Always preserve the user requested cpumask") fixes this problem asuser_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit851a723e45d1("sched: Always clearuser_cpus_ptrindo_set_cpus_allowed()") which allows the clearing ofuser_cpus_ptrindo_set_cpus_allowed(). This time, it will affect all arches.
Quoted 6 lines
Fix this bug by always clearing the
user_cpus_ptrof the newly cloned/forked task before the copying process starts and check theuser_cpus_ptrstate of the source task underpi_lock.Note to stable, this patch won't be applicable to stable releases. Just copy the new
dup_user_cpus_ptr()function over.
I have a note here about what to do when backporting to stable. Just copy the new function over will be fine.
Cheers,
Longman
Quoted 9 lines
Fixes 07ec77a1d4e8 ("sched: Allow task CPU affinity to be restricted on asymmetric systems")Fixes 851a723e45d1 ("sched: Always clear user_cpus_ptr in do_set_cpus_allowed()")Reported-by David Wang 王标 <[email protected]>Signed-off-by Waiman Long <[email protected]>Signed-off-by Ingo Molnar <[email protected]>Reviewed-by Peter Zijlstra <[email protected]>
Quoted 43 lines · Waiman Long
Quoted 42 lines · On 1/14/23 04:53, [email protected] wrote:
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Possible dependencies:
87ca4f9efbd7("sched/core: Fix use-after-free bug indup_user_cpus_ptr()")8f9ea86fdf99("sched: Always preserve the user requested cpumask")713a2e21a513("sched: Introduceaffinity_context")thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
87ca4f9efbd7cc649ff43b87970888f2812945b8Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug indup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitSince commit
07ec77a1d4e8("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing ofuser_cpus_ptrare done underpi_lockfor arm64 architecture. However,dup_user_cpus_ptr()accessesuser_cpus_ptrwithout any lock protection. Sincesched_setaffinity()can be invoked from another process, the process being modified may be undergoingfork()at the same time. When racing with the clearing ofuser_cpus_ptrin__set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.Commit
8f9ea86fdf99("sched: Always preserve the user requested cpumask") fixes this problem asuser_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit851a723e45d1("sched: Always clearuser_cpus_ptrindo_set_cpus_allowed()") which allows the clearing ofuser_cpus_ptrindo_set_cpus_allowed(). This time, it will affect all arches.
Quoted 8 lines
Quoted 6 lines
Fix this bug by always clearing the
user_cpus_ptrof the newly cloned/forked task before the copying process starts and check theuser_cpus_ptrstate of the source task underpi_lock.Note to stable, this patch won't be applicable to stable releases. Just copy the new
dup_user_cpus_ptr()function over.I have a note here about what to do when backporting to stable. Just copy the new function over will be fine.
That will be before the application of the subsequent patch which will modify it in a way for suitable for stable. I can send out a separate stable patch for that later today.
Cheers,
Longman
Waiman Long
Reviewed-by Peter ZijlstraQuoted 48 lines · Waiman Long
Quoted 47 lines · Waiman Long
Quoted 46 lines · On 1/14/23 04:53, [email protected] wrote:
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Possible dependencies:
87ca4f9efbd7("sched/core: Fix use-after-free bug indup_user_cpus_ptr()")8f9ea86fdf99("sched: Always preserve the user requested cpumask")713a2e21a513("sched: Introduceaffinity_context")thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
87ca4f9efbd7cc649ff43b87970888f2812945b8Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug indup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitSince commit
07ec77a1d4e8("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing ofuser_cpus_ptrare done underpi_lockfor arm64 architecture. However,dup_user_cpus_ptr()accessesuser_cpus_ptrwithout any lock protection. Sincesched_setaffinity()can be invoked from another process, the process being modified may be undergoingfork()at the same time. When racing with the clearing ofuser_cpus_ptrin__set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.Commit
8f9ea86fdf99("sched: Always preserve the user requested cpumask") fixes this problem asuser_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit851a723e45d1("sched: Always clearuser_cpus_ptrindo_set_cpus_allowed()") which allows the clearing ofuser_cpus_ptrindo_set_cpus_allowed(). This time, it will affect all arches.Fix this bug by always clearing the
user_cpus_ptrof the newly cloned/forked task before the copying process starts and check theuser_cpus_ptrstate of the source task underpi_lock.
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
Note to stable, this patch won't be applicable to stable releases. Just copy the new
dup_user_cpus_ptr()function over.I have a note here about what to do when backporting to stable. Just copy the new function over will be fine.
That will be before the application of the subsequent patch which will modify it in a way for suitable for stable. I can send out a separate stable patch for that later today.
The attached patch will apply to linux-6.1.y as well as linux-5.15.y.
Cheers,
Longman
From 36feebbfa2b18a02102f136fdfaa53a7f25830d8 Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Sat, 14 Jan 2023 20:05:34 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug in dup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit 87ca4f9efbd7cc649ff43b87970888f2812945b8 upstream.
Since commit 07ec77a1d4e8 ("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing of user_cpus_ptr are done under pi_lock for arm64 architecture. However, dup_user_cpus_ptr() accesses user_cpus_ptr without any lock protection. Since sched_setaffinity() can be invoked from another process, the process being modified may be undergoing fork() at the same time. When racing with the clearing of user_cpus_ptr in __set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.
Commit 8f9ea86fdf99 ("sched: Always preserve the user requested cpumask") fixes this problem as user_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit 851a723e45d1 ("sched: Always clear user_cpus_ptr in do_set_cpus_allowed()") which allows the clearing of user_cpus_ptr in do_set_cpus_allowed(). This time, it will affect all arches.
Fix this bug by always clearing the user_cpus_ptr of the newly cloned/forked task before the copying process starts and check the user_cpus_ptr state of the source task under pi_lock.
Note to stable, this patch won't be applicable to stable releases. Just copy the new dup_user_cpus_ptr() function over.
--- kernel/sched/core.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-)
kernel/sched/core.c +33 -4
@@ -2587,14 +2587,43 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)int dup_user_cpus_ptr (struct task_struct *dst,struct task_struct *src,int node) { -if (!src->user_cpus_ptr) +cpumask_t *user_mask; +unsigned long flags; + +/* +* Always clear dst->user_cpus_ptr first as their user_cpus_ptr's +* may differ by now due to racing. +*/ + dst->user_cpus_ptr =NULL ; + +/* +* This check is racy and losing the race is a valid situation. +* It is not worth the extra overhead of taking the pi_lock on +* every fork/clone. +*/ +if (data_race (!src->user_cpus_ptr))return 0 ; - dst->user_cpus_ptr =kmalloc_node (cpumask_size (),GFP_KERNEL , node); -if (!dst->user_cpus_ptr) + user_mask =kmalloc_node (cpumask_size (),GFP_KERNEL , node); +if (!user_mask)return -ENOMEM ; -cpumask_copy (dst->user_cpus_ptr, src->user_cpus_ptr); +/* +* Use pi_lock to protect content of user_cpus_ptr +* +* Though unlikely, user_cpus_ptr can be reset to NULL by a concurrent +* do_set_cpus_allowed(). +*/ +raw_spin_lock_irqsave (&src->pi_lock, flags); +if (src->user_cpus_ptr) { +swap (dst->user_cpus_ptr, user_mask); +cpumask_copy (dst->user_cpus_ptr, src->user_cpus_ptr); + } +raw_spin_unlock_irqrestore (&src->pi_lock, flags); + +if (unlikely (user_mask)) +kfree (user_mask); +return 0 ; }
Signature · 1 line
2.31.1
Greg KH
maintainerQuoted 55 lines · Waiman Long
Quoted 53 lines · Waiman Long
Quoted 52 lines · Waiman Long
Quoted 50 lines · On 1/14/23 04:53, [email protected] wrote:
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Possible dependencies:
87ca4f9efbd7("sched/core: Fix use-after-free bug indup_user_cpus_ptr()")8f9ea86fdf99("sched: Always preserve the user requested cpumask")713a2e21a513("sched: Introduceaffinity_context")thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
87ca4f9efbd7cc649ff43b87970888f2812945b8Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug indup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitSince commit
07ec77a1d4e8("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing ofuser_cpus_ptrare done underpi_lockfor arm64 architecture. However,dup_user_cpus_ptr()accessesuser_cpus_ptrwithout any lock protection. Sincesched_setaffinity()can be invoked from another process, the process being modified may be undergoingfork()at the same time. When racing with the clearing ofuser_cpus_ptrin__set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.Commit
8f9ea86fdf99("sched: Always preserve the user requested cpumask") fixes this problem asuser_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit851a723e45d1("sched: Always clearuser_cpus_ptrindo_set_cpus_allowed()") which allows the clearing ofuser_cpus_ptrindo_set_cpus_allowed(). This time, it will affect all arches.Fix this bug by always clearing the
user_cpus_ptrof the newly cloned/forked task before the copying process starts and check theuser_cpus_ptrstate of the source task underpi_lock.Note to stable, this patch won't be applicable to stable releases. Just copy the new
dup_user_cpus_ptr()function over.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
I have a note here about what to do when backporting to stable. Just copy the new function over will be fine.
That will be before the application of the subsequent patch which will modify it in a way for suitable for stable. I can send out a separate stable patch for that later today.
The attached patch will apply to linux-6.1.y as well as linux-5.15.y.
Thanks for the backport, now queued up.
greg k-h
Ingo Molnar
Acked-byQuoted 55 lines · Waiman Long
Quoted 53 lines · Waiman Long
Quoted 52 lines · Waiman Long
Quoted 50 lines · On 1/14/23 04:53, [email protected] wrote:
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.Possible dependencies:
87ca4f9efbd7("sched/core: Fix use-after-free bug indup_user_cpus_ptr()")8f9ea86fdf99("sched: Always preserve the user requested cpumask")713a2e21a513("sched: Introduceaffinity_context")thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From
87ca4f9efbd7cc649ff43b87970888f2812945b8Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Fri, 30 Dec 2022 23:11:19 -0500
Subject: [PATCH] sched/core: Fix use-after-free bug indup_user_cpus_ptr()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bitSince commit
07ec77a1d4e8("sched: Allow task CPU affinity to be restricted on asymmetric systems"), the setting and clearing ofuser_cpus_ptrare done underpi_lockfor arm64 architecture. However,dup_user_cpus_ptr()accessesuser_cpus_ptrwithout any lock protection. Sincesched_setaffinity()can be invoked from another process, the process being modified may be undergoingfork()at the same time. When racing with the clearing ofuser_cpus_ptrin__set_cpus_allowed_ptr_locked(), it can lead to user-after-free and possibly double-free in arm64 kernel.Commit
8f9ea86fdf99("sched: Always preserve the user requested cpumask") fixes this problem asuser_cpus_ptr, once set, will never be cleared in a task's lifetime. However, this bug was re-introduced in commit851a723e45d1("sched: Always clearuser_cpus_ptrindo_set_cpus_allowed()") which allows the clearing ofuser_cpus_ptrindo_set_cpus_allowed(). This time, it will affect all arches.Fix this bug by always clearing the
user_cpus_ptrof the newly cloned/forked task before the copying process starts and check theuser_cpus_ptrstate of the source task underpi_lock.Note to stable, this patch won't be applicable to stable releases. Just copy the new
dup_user_cpus_ptr()function over.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
I have a note here about what to do when backporting to stable. Just copy the new function over will be fine.
That will be before the application of the subsequent patch which will modify it in a way for suitable for stable. I can send out a separate stable patch for that later today.
The attached patch will apply to linux-6.1.y as well as linux-5.15.y.
Thanks!
Ingo