lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <20151006195727.GI11639@twins.programming.kicks-ass.net> Date: Tue, 6 Oct 2015 21:57:27 +0200 From: Peter Zijlstra <peterz@...radead.org> To: Oleg Nesterov <oleg@...hat.com> Cc: Boqun Feng <boqun.feng@...il.com>, "Paul E. McKenney" <paulmck@...ux.vnet.ibm.com>, linux-kernel@...r.kernel.org, linux-doc@...r.kernel.org, Jonathan Corbet <corbet@....net>, Michal Hocko <mhocko@...nel.org>, David Howells <dhowells@...hat.com>, Linus Torvalds <torvalds@...ux-foundation.org>, Will Deacon <will.deacon@....com> Subject: Re: [PATCH] Documentation: Remove misleading examples of the barriers in wake_*() > On Mon, Sep 21, 2015 at 07:46:11PM +0200, Oleg Nesterov wrote: > > In short, I got lost ;) Now I don't even understand why we do not need > > another rmb() between p->on_rq and p->on_cpu. Suppose a thread T does > > > > set_current_state(...); > > schedule(); > > > > it can be preempted in between, after that we have "on_rq && !on_cpu". > > Then it gets CPU again and calls schedule() which clears on_rq. > > > > What guarantees that if ttwu() sees on_rq == 0 cleared by schedule() > > then it can _not_ still see the old value of on_cpu == 0? I think you're right. Does the below adequately explain things? I'll have another look tomorrow to see if I still agree with myself, but for now I think I've convinced myself you're right. --- Subject: sched: Fix race in try_to_wake_up() vs schedule() Oleg noticed that its possible to falsely observe p->on_cpu == 0 such that we'll prematurely continue with the wakeup and effectively run p on two CPUs at the same time. Even though the overlap is very limited; the task is in the middle of being scheduled out; it could still result in corruption of the scheduler data structures. CPU0 CPU1 set_current_state(...) <preempt_schedule> context_switch(X, Y) prepare_lock_switch(Y) Y->on_cpu = 1; finish_lock_switch(X) store_release(X->on_cpu, 0); try_to_wake_up(X) LOCK(p->pi_lock); t = X->on_cpu; // 0 context_switch(Y, X) prepare_lock_switch(X) X->on_cpu = 1; finish_lock_switch(Y) store_release(Y->on_cpu, 0); </preempt_schedule> schedule(); deactivate_task(X); X->on_rq = 0; if (X->on_rq) // false if (t) while (X->on_cpu) cpu_relax(); context_switch(X, ..) finish_lock_switch(X) store_release(X->on_cpu, 0); Avoid the load of X->on_cpu being hoisted over the X->on_rq load. Reported-by: Oleg Nesterov <oleg@...hat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@...radead.org> --- kernel/sched/core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2084,6 +2084,25 @@ try_to_wake_up(struct task_struct *p, un #ifdef CONFIG_SMP /* + * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be + * possible to, falsely, observe p->on_cpu == 0. + * + * One must be running (->on_cpu == 1) in order to remove oneself + * from the runqueue. + * + * [S] ->on_cpu = 1; [L] ->on_rq + * UNLOCK rq->lock + * RMB + * LOCK rq->lock + * [S] ->on_rq = 0; [L] ->on_cpu + * + * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock + * from the consecutive calls to schedule(); the first switching to our + * task, the second putting it to sleep. + */ + smp_rmb(); + + /* * If the owning (remote) cpu is still in the middle of schedule() with * this task as prev, wait until its done referencing the task. */ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists