Skip to content

Commit d4f754c

Browse files
committed
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
2 parents eb0ef8a + 91dabf3 commit d4f754c

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

kernel/rseq.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,20 +171,35 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
171171
return 0;
172172
}
173173

174+
static bool rseq_warn_flags(const char *str, u32 flags)
175+
{
176+
u32 test_flags;
177+
178+
if (!flags)
179+
return false;
180+
test_flags = flags & RSEQ_CS_NO_RESTART_FLAGS;
181+
if (test_flags)
182+
pr_warn_once("Deprecated flags (%u) in %s ABI structure", test_flags, str);
183+
test_flags = flags & ~RSEQ_CS_NO_RESTART_FLAGS;
184+
if (test_flags)
185+
pr_warn_once("Unknown flags (%u) in %s ABI structure", test_flags, str);
186+
return true;
187+
}
188+
174189
static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
175190
{
176191
u32 flags, event_mask;
177192
int ret;
178193

179-
if (WARN_ON_ONCE(cs_flags & RSEQ_CS_NO_RESTART_FLAGS) || cs_flags)
194+
if (rseq_warn_flags("rseq_cs", cs_flags))
180195
return -EINVAL;
181196

182197
/* Get thread flags. */
183198
ret = get_user(flags, &t->rseq->flags);
184199
if (ret)
185200
return ret;
186201

187-
if (WARN_ON_ONCE(flags & RSEQ_CS_NO_RESTART_FLAGS) || flags)
202+
if (rseq_warn_flags("rseq", flags))
188203
return -EINVAL;
189204

190205
/*

kernel/sched/core.c

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4200,6 +4200,40 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
42004200
return success;
42014201
}
42024202

4203+
static bool __task_needs_rq_lock(struct task_struct *p)
4204+
{
4205+
unsigned int state = READ_ONCE(p->__state);
4206+
4207+
/*
4208+
* Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
4209+
* the task is blocked. Make sure to check @state since ttwu() can drop
4210+
* locks at the end, see ttwu_queue_wakelist().
4211+
*/
4212+
if (state == TASK_RUNNING || state == TASK_WAKING)
4213+
return true;
4214+
4215+
/*
4216+
* Ensure we load p->on_rq after p->__state, otherwise it would be
4217+
* possible to, falsely, observe p->on_rq == 0.
4218+
*
4219+
* See try_to_wake_up() for a longer comment.
4220+
*/
4221+
smp_rmb();
4222+
if (p->on_rq)
4223+
return true;
4224+
4225+
#ifdef CONFIG_SMP
4226+
/*
4227+
* Ensure the task has finished __schedule() and will not be referenced
4228+
* anymore. Again, see try_to_wake_up() for a longer comment.
4229+
*/
4230+
smp_rmb();
4231+
smp_cond_load_acquire(&p->on_cpu, !VAL);
4232+
#endif
4233+
4234+
return false;
4235+
}
4236+
42034237
/**
42044238
* task_call_func - Invoke a function on task in fixed state
42054239
* @p: Process for which the function is to be invoked, can be @current.
@@ -4217,28 +4251,12 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
42174251
int task_call_func(struct task_struct *p, task_call_f func, void *arg)
42184252
{
42194253
struct rq *rq = NULL;
4220-
unsigned int state;
42214254
struct rq_flags rf;
42224255
int ret;
42234256

42244257
raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
42254258

4226-
state = READ_ONCE(p->__state);
4227-
4228-
/*
4229-
* Ensure we load p->on_rq after p->__state, otherwise it would be
4230-
* possible to, falsely, observe p->on_rq == 0.
4231-
*
4232-
* See try_to_wake_up() for a longer comment.
4233-
*/
4234-
smp_rmb();
4235-
4236-
/*
4237-
* Since pi->lock blocks try_to_wake_up(), we don't need rq->lock when
4238-
* the task is blocked. Make sure to check @state since ttwu() can drop
4239-
* locks at the end, see ttwu_queue_wakelist().
4240-
*/
4241-
if (state == TASK_RUNNING || state == TASK_WAKING || p->on_rq)
4259+
if (__task_needs_rq_lock(p))
42424260
rq = __task_rq_lock(p, &rf);
42434261

42444262
/*

0 commit comments

Comments
 (0)