- Fix a small race on the task's exit path where there's a
misunderstanding whether the task holds rq->lock or not - Prevent processes from getting killed when using deprecated or unknown rseq ABI flags in order to be able to fuzz the rseq() syscall with syzkaller -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmN6FH0ACgkQEsHwGGHe VUrsFw//QdGg/ZpGdeGH5njOFX9KCLrcMojz+Ip7vn4TeWiT/0J70jym4Pxkvwls Cz1s47kmhEE56xYi0gMJJi6XtjYWh1/sptuTkS+wHNp+NliaHMnmPPY08wL6/ZEq Zm8KP1e3OHjl+k82yhuIeYAFFdUpbLlQkjCKHqQkBlemh0MF+GeTavHDWe3kLolb arEld+kIo7OUkBDmVGk6BaE3R0DuCYGokDcj9xGNx0alcQCtu+oT+T9jYMgwBIn2 zGpfM2jeB4nwYKYv+Mg6tY38vaz6bHZWSoDhaB/+GzewhZMdGGCo3SdN207WJHUK TSjjz6a5sMJSZTpVW0K6MxJhv245KNt3Tc/JpDtqVq4KfKNcv0Rs4bDIWWyIsvow KlSUvRBeDT3rx9152vB72GiPptZogWsTc5dM0/ZlBaCfM4UBreYgO37ZYYK9hPdx M2rCOafUSwkDFG+A5JCWM7d5sPAndvAAX29qqmrgbTVSV+XKAx3UdWpGJTEL8bSF OWIFhVd2nqOglL41c1Rm4zk9TJ3k9mMsgnsuskgclmAI7GmRkPADHlv19bRRe8UL TEDBOCQaNYFkjkp+4IM/I3GXGa+SiOHEiK7G2CjJEeHbzWoGKQPFpJtOtH4zHNV+ m32Ek2XBw1zKjfAyr1WGyA+GE4tTIIphqgonu4cA2cKCYjm/SG4= =I+nD -----END PGP SIGNATURE----- Merge tag 'sched_urgent_for_v6.1_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull scheduler fixes from Borislav Petkov: - Fix a small race on the task's exit path where there's a misunderstanding whether the task holds rq->lock or not - Prevent processes from getting killed when using deprecated or unknown rseq ABI flags in order to be able to fuzz the rseq() syscall with syzkaller * tag 'sched_urgent_for_v6.1_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: sched: Fix race in task_call_func() rseq: Use pr_warn_once() when deprecated/unknown ABI flags are encountered
This commit is contained in:
commit
d4f754c361
@ -171,12 +171,27 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool rseq_warn_flags(const char *str, u32 flags)
|
||||
{
|
||||
u32 test_flags;
|
||||
|
||||
if (!flags)
|
||||
return false;
|
||||
test_flags = flags & RSEQ_CS_NO_RESTART_FLAGS;
|
||||
if (test_flags)
|
||||
pr_warn_once("Deprecated flags (%u) in %s ABI structure", test_flags, str);
|
||||
test_flags = flags & ~RSEQ_CS_NO_RESTART_FLAGS;
|
||||
if (test_flags)
|
||||
pr_warn_once("Unknown flags (%u) in %s ABI structure", test_flags, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
|
||||
{
|
||||
u32 flags, event_mask;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(cs_flags & RSEQ_CS_NO_RESTART_FLAGS) || cs_flags)
|
||||
if (rseq_warn_flags("rseq_cs", cs_flags))
|
||||
return -EINVAL;
|
||||
|
||||
/* Get thread flags. */
|
||||
@ -184,7 +199,7 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON_ONCE(flags & RSEQ_CS_NO_RESTART_FLAGS) || flags)
|
||||
if (rseq_warn_flags("rseq", flags))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
@ -4200,6 +4200,40 @@ out:
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool __task_needs_rq_lock(struct task_struct *p)
|
||||
{
|
||||
unsigned int state = READ_ONCE(p->__state);
|
||||
|
||||
/*
|
||||
* Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
|
||||
* the task is blocked. Make sure to check @state since ttwu() can drop
|
||||
* locks at the end, see ttwu_queue_wakelist().
|
||||
*/
|
||||
if (state == TASK_RUNNING || state == TASK_WAKING)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Ensure we load p->on_rq after p->__state, otherwise it would be
|
||||
* possible to, falsely, observe p->on_rq == 0.
|
||||
*
|
||||
* See try_to_wake_up() for a longer comment.
|
||||
*/
|
||||
smp_rmb();
|
||||
if (p->on_rq)
|
||||
return true;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Ensure the task has finished __schedule() and will not be referenced
|
||||
* anymore. Again, see try_to_wake_up() for a longer comment.
|
||||
*/
|
||||
smp_rmb();
|
||||
smp_cond_load_acquire(&p->on_cpu, !VAL);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* task_call_func - Invoke a function on task in fixed state
|
||||
* @p: Process for which the function is to be invoked, can be @current.
|
||||
@ -4217,28 +4251,12 @@ out:
|
||||
int task_call_func(struct task_struct *p, task_call_f func, void *arg)
|
||||
{
|
||||
struct rq *rq = NULL;
|
||||
unsigned int state;
|
||||
struct rq_flags rf;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
|
||||
|
||||
state = READ_ONCE(p->__state);
|
||||
|
||||
/*
|
||||
* Ensure we load p->on_rq after p->__state, otherwise it would be
|
||||
* possible to, falsely, observe p->on_rq == 0.
|
||||
*
|
||||
* See try_to_wake_up() for a longer comment.
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
/*
|
||||
* Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
|
||||
* the task is blocked. Make sure to check @state since ttwu() can drop
|
||||
* locks at the end, see ttwu_queue_wakelist().
|
||||
*/
|
||||
if (state == TASK_RUNNING || state == TASK_WAKING || p->on_rq)
|
||||
if (__task_needs_rq_lock(p))
|
||||
rq = __task_rq_lock(p, &rf);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user