Merge branch 'sched/urgent' into sched/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
这个提交包含在:
@@ -218,47 +218,84 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
|
||||
static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, u32 delta,
|
||||
u32 curr, const bool probe_pass)
|
||||
{
|
||||
const s64 imm_min = S32_MIN, imm_max = S32_MAX;
|
||||
s64 imm = insn->imm;
|
||||
|
||||
if (curr < pos && curr + imm + 1 > pos)
|
||||
imm += delta;
|
||||
else if (curr > pos + delta && curr + imm + 1 <= pos + delta)
|
||||
imm -= delta;
|
||||
if (imm < imm_min || imm > imm_max)
|
||||
return -ERANGE;
|
||||
if (!probe_pass)
|
||||
insn->imm = imm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, u32 delta,
|
||||
u32 curr, const bool probe_pass)
|
||||
{
|
||||
const s32 off_min = S16_MIN, off_max = S16_MAX;
|
||||
s32 off = insn->off;
|
||||
|
||||
if (curr < pos && curr + off + 1 > pos)
|
||||
off += delta;
|
||||
else if (curr > pos + delta && curr + off + 1 <= pos + delta)
|
||||
off -= delta;
|
||||
if (off < off_min || off > off_max)
|
||||
return -ERANGE;
|
||||
if (!probe_pass)
|
||||
insn->off = off;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta,
|
||||
const bool probe_pass)
|
||||
{
|
||||
u32 i, insn_cnt = prog->len + (probe_pass ? delta : 0);
|
||||
struct bpf_insn *insn = prog->insnsi;
|
||||
u32 i, insn_cnt = prog->len;
|
||||
bool pseudo_call;
|
||||
u8 code;
|
||||
int off;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < insn_cnt; i++, insn++) {
|
||||
code = insn->code;
|
||||
if (BPF_CLASS(code) != BPF_JMP)
|
||||
continue;
|
||||
if (BPF_OP(code) == BPF_EXIT)
|
||||
continue;
|
||||
if (BPF_OP(code) == BPF_CALL) {
|
||||
if (insn->src_reg == BPF_PSEUDO_CALL)
|
||||
pseudo_call = true;
|
||||
else
|
||||
continue;
|
||||
} else {
|
||||
pseudo_call = false;
|
||||
u8 code;
|
||||
|
||||
/* In the probing pass we still operate on the original,
|
||||
* unpatched image in order to check overflows before we
|
||||
* do any other adjustments. Therefore skip the patchlet.
|
||||
*/
|
||||
if (probe_pass && i == pos) {
|
||||
i += delta + 1;
|
||||
insn++;
|
||||
}
|
||||
off = pseudo_call ? insn->imm : insn->off;
|
||||
|
||||
/* Adjust offset of jmps if we cross boundaries. */
|
||||
if (i < pos && i + off + 1 > pos)
|
||||
off += delta;
|
||||
else if (i > pos + delta && i + off + 1 <= pos + delta)
|
||||
off -= delta;
|
||||
|
||||
if (pseudo_call)
|
||||
insn->imm = off;
|
||||
else
|
||||
insn->off = off;
|
||||
code = insn->code;
|
||||
if (BPF_CLASS(code) != BPF_JMP ||
|
||||
BPF_OP(code) == BPF_EXIT)
|
||||
continue;
|
||||
/* Adjust offset of jmps if we cross patch boundaries. */
|
||||
if (BPF_OP(code) == BPF_CALL) {
|
||||
if (insn->src_reg != BPF_PSEUDO_CALL)
|
||||
continue;
|
||||
ret = bpf_adj_delta_to_imm(insn, pos, delta, i,
|
||||
probe_pass);
|
||||
} else {
|
||||
ret = bpf_adj_delta_to_off(insn, pos, delta, i,
|
||||
probe_pass);
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
const struct bpf_insn *patch, u32 len)
|
||||
{
|
||||
u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
|
||||
const u32 cnt_max = S16_MAX;
|
||||
struct bpf_prog *prog_adj;
|
||||
|
||||
/* Since our patchlet doesn't expand the image, we're done. */
|
||||
@@ -269,6 +306,15 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
|
||||
insn_adj_cnt = prog->len + insn_delta;
|
||||
|
||||
/* Reject anything that would potentially let the insn->off
|
||||
* target overflow when we have excessive program expansions.
|
||||
* We need to probe here before we do any reallocation where
|
||||
* we afterwards may not fail anymore.
|
||||
*/
|
||||
if (insn_adj_cnt > cnt_max &&
|
||||
bpf_adj_branches(prog, off, insn_delta, true))
|
||||
return NULL;
|
||||
|
||||
/* Several new instructions need to be inserted. Make room
|
||||
* for them. Likely, there's no need for a new allocation as
|
||||
* last page could have large enough tailroom.
|
||||
@@ -294,7 +340,11 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
sizeof(*patch) * insn_rest);
|
||||
memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);
|
||||
|
||||
bpf_adj_branches(prog_adj, off, insn_delta);
|
||||
/* We are guaranteed to not fail at this point, otherwise
|
||||
* the ship has sailed to reverse to the original state. An
|
||||
* overflow cannot happen at this point.
|
||||
*/
|
||||
BUG_ON(bpf_adj_branches(prog_adj, off, insn_delta, false));
|
||||
|
||||
return prog_adj;
|
||||
}
|
||||
|
@@ -1703,11 +1703,11 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
|
||||
* we increment the refcnt. If this is the case abort with an
|
||||
* error.
|
||||
*/
|
||||
verdict = bpf_prog_inc_not_zero(stab->bpf_verdict);
|
||||
verdict = bpf_prog_inc_not_zero(verdict);
|
||||
if (IS_ERR(verdict))
|
||||
return PTR_ERR(verdict);
|
||||
|
||||
parse = bpf_prog_inc_not_zero(stab->bpf_parse);
|
||||
parse = bpf_prog_inc_not_zero(parse);
|
||||
if (IS_ERR(parse)) {
|
||||
bpf_prog_put(verdict);
|
||||
return PTR_ERR(parse);
|
||||
@@ -1715,12 +1715,12 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
|
||||
}
|
||||
|
||||
if (tx_msg) {
|
||||
tx_msg = bpf_prog_inc_not_zero(stab->bpf_tx_msg);
|
||||
tx_msg = bpf_prog_inc_not_zero(tx_msg);
|
||||
if (IS_ERR(tx_msg)) {
|
||||
if (verdict)
|
||||
bpf_prog_put(verdict);
|
||||
if (parse)
|
||||
if (parse && verdict) {
|
||||
bpf_prog_put(parse);
|
||||
bpf_prog_put(verdict);
|
||||
}
|
||||
return PTR_ERR(tx_msg);
|
||||
}
|
||||
}
|
||||
@@ -1805,10 +1805,10 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
|
||||
out_free:
|
||||
smap_release_sock(psock, sock);
|
||||
out_progs:
|
||||
if (verdict)
|
||||
bpf_prog_put(verdict);
|
||||
if (parse)
|
||||
if (parse && verdict) {
|
||||
bpf_prog_put(parse);
|
||||
bpf_prog_put(verdict);
|
||||
}
|
||||
if (tx_msg)
|
||||
bpf_prog_put(tx_msg);
|
||||
write_unlock_bh(&sock->sk_callback_lock);
|
||||
|
@@ -978,7 +978,7 @@ static bool register_is_null(struct bpf_reg_state *reg)
|
||||
*/
|
||||
static int check_stack_write(struct bpf_verifier_env *env,
|
||||
struct bpf_func_state *state, /* func where register points to */
|
||||
int off, int size, int value_regno)
|
||||
int off, int size, int value_regno, int insn_idx)
|
||||
{
|
||||
struct bpf_func_state *cur; /* state of the current function */
|
||||
int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err;
|
||||
@@ -1017,8 +1017,33 @@ static int check_stack_write(struct bpf_verifier_env *env,
|
||||
state->stack[spi].spilled_ptr = cur->regs[value_regno];
|
||||
state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN;
|
||||
|
||||
for (i = 0; i < BPF_REG_SIZE; i++)
|
||||
for (i = 0; i < BPF_REG_SIZE; i++) {
|
||||
if (state->stack[spi].slot_type[i] == STACK_MISC &&
|
||||
!env->allow_ptr_leaks) {
|
||||
int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off;
|
||||
int soff = (-spi - 1) * BPF_REG_SIZE;
|
||||
|
||||
/* detected reuse of integer stack slot with a pointer
|
||||
* which means either llvm is reusing stack slot or
|
||||
* an attacker is trying to exploit CVE-2018-3639
|
||||
* (speculative store bypass)
|
||||
* Have to sanitize that slot with preemptive
|
||||
* store of zero.
|
||||
*/
|
||||
if (*poff && *poff != soff) {
|
||||
/* disallow programs where single insn stores
|
||||
* into two different stack slots, since verifier
|
||||
* cannot sanitize them
|
||||
*/
|
||||
verbose(env,
|
||||
"insn %d cannot access two stack slots fp%d and fp%d",
|
||||
insn_idx, *poff, soff);
|
||||
return -EINVAL;
|
||||
}
|
||||
*poff = soff;
|
||||
}
|
||||
state->stack[spi].slot_type[i] = STACK_SPILL;
|
||||
}
|
||||
} else {
|
||||
u8 type = STACK_MISC;
|
||||
|
||||
@@ -1694,7 +1719,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
||||
|
||||
if (t == BPF_WRITE)
|
||||
err = check_stack_write(env, state, off, size,
|
||||
value_regno);
|
||||
value_regno, insn_idx);
|
||||
else
|
||||
err = check_stack_read(env, state, off, size,
|
||||
value_regno);
|
||||
@@ -5169,6 +5194,34 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
|
||||
else
|
||||
continue;
|
||||
|
||||
if (type == BPF_WRITE &&
|
||||
env->insn_aux_data[i + delta].sanitize_stack_off) {
|
||||
struct bpf_insn patch[] = {
|
||||
/* Sanitize suspicious stack slot with zero.
|
||||
* There are no memory dependencies for this store,
|
||||
* since it's only using frame pointer and immediate
|
||||
* constant of zero
|
||||
*/
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_FP,
|
||||
env->insn_aux_data[i + delta].sanitize_stack_off,
|
||||
0),
|
||||
/* the original STX instruction will immediately
|
||||
* overwrite the same stack slot with appropriate value
|
||||
*/
|
||||
*insn,
|
||||
};
|
||||
|
||||
cnt = ARRAY_SIZE(patch);
|
||||
new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
delta += cnt - 1;
|
||||
env->prog = new_prog;
|
||||
insn = new_prog->insnsi + i + delta;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
|
||||
continue;
|
||||
|
||||
|
@@ -193,7 +193,7 @@ EXPORT_SYMBOL_GPL(kthread_parkme);
|
||||
|
||||
void kthread_park_complete(struct task_struct *k)
|
||||
{
|
||||
complete(&to_kthread(k)->parked);
|
||||
complete_all(&to_kthread(k)->parked);
|
||||
}
|
||||
|
||||
static int kthread(void *_create)
|
||||
@@ -459,6 +459,7 @@ void kthread_unpark(struct task_struct *k)
|
||||
if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
|
||||
__kthread_bind(k, kthread->cpu, TASK_PARKED);
|
||||
|
||||
reinit_completion(&kthread->parked);
|
||||
clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
|
||||
wake_up_state(k, TASK_PARKED);
|
||||
}
|
||||
@@ -483,9 +484,6 @@ int kthread_park(struct task_struct *k)
|
||||
if (WARN_ON(k->flags & PF_EXITING))
|
||||
return -ENOSYS;
|
||||
|
||||
if (WARN_ON_ONCE(test_bit(KTHREAD_SHOULD_PARK, &kthread->flags)))
|
||||
return -EBUSY;
|
||||
|
||||
set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
|
||||
if (k != current) {
|
||||
wake_up_process(k);
|
||||
|
@@ -352,16 +352,15 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
|
||||
struct task_struct *owner;
|
||||
bool ret = true;
|
||||
|
||||
BUILD_BUG_ON(!rwsem_has_anonymous_owner(RWSEM_OWNER_UNKNOWN));
|
||||
|
||||
if (need_resched())
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
owner = READ_ONCE(sem->owner);
|
||||
if (!rwsem_owner_is_writer(owner)) {
|
||||
/*
|
||||
* Don't spin if the rwsem is readers owned.
|
||||
*/
|
||||
ret = !rwsem_owner_is_reader(owner);
|
||||
if (!owner || !is_rwsem_owner_spinnable(owner)) {
|
||||
ret = !owner; /* !owner is spinnable */
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -382,11 +381,11 @@ static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem)
|
||||
{
|
||||
struct task_struct *owner = READ_ONCE(sem->owner);
|
||||
|
||||
if (!rwsem_owner_is_writer(owner))
|
||||
goto out;
|
||||
if (!is_rwsem_owner_spinnable(owner))
|
||||
return false;
|
||||
|
||||
rcu_read_lock();
|
||||
while (sem->owner == owner) {
|
||||
while (owner && (READ_ONCE(sem->owner) == owner)) {
|
||||
/*
|
||||
* Ensure we emit the owner->on_cpu, dereference _after_
|
||||
* checking sem->owner still matches owner, if that fails,
|
||||
@@ -408,12 +407,12 @@ static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem)
|
||||
cpu_relax();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
|
||||
/*
|
||||
* If there is a new owner or the owner is not set, we continue
|
||||
* spinning.
|
||||
*/
|
||||
return !rwsem_owner_is_reader(READ_ONCE(sem->owner));
|
||||
return is_rwsem_owner_spinnable(READ_ONCE(sem->owner));
|
||||
}
|
||||
|
||||
static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
|
||||
|
@@ -221,5 +221,3 @@ void up_read_non_owner(struct rw_semaphore *sem)
|
||||
EXPORT_SYMBOL(up_read_non_owner);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -1,20 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* The owner field of the rw_semaphore structure will be set to
|
||||
* RWSEM_READ_OWNED when a reader grabs the lock. A writer will clear
|
||||
* RWSEM_READER_OWNED when a reader grabs the lock. A writer will clear
|
||||
* the owner field when it unlocks. A reader, on the other hand, will
|
||||
* not touch the owner field when it unlocks.
|
||||
*
|
||||
* In essence, the owner field now has the following 3 states:
|
||||
* In essence, the owner field now has the following 4 states:
|
||||
* 1) 0
|
||||
* - lock is free or the owner hasn't set the field yet
|
||||
* 2) RWSEM_READER_OWNED
|
||||
* - lock is currently or previously owned by readers (lock is free
|
||||
* or not set by owner yet)
|
||||
* 3) Other non-zero value
|
||||
* - a writer owns the lock
|
||||
* 3) RWSEM_ANONYMOUSLY_OWNED bit set with some other bits set as well
|
||||
* - lock is owned by an anonymous writer, so spinning on the lock
|
||||
* owner should be disabled.
|
||||
* 4) Other non-zero value
|
||||
* - a writer owns the lock and other writers can spin on the lock owner.
|
||||
*/
|
||||
#define RWSEM_READER_OWNED ((struct task_struct *)1UL)
|
||||
#define RWSEM_ANONYMOUSLY_OWNED (1UL << 0)
|
||||
#define RWSEM_READER_OWNED ((struct task_struct *)RWSEM_ANONYMOUSLY_OWNED)
|
||||
|
||||
#ifdef CONFIG_DEBUG_RWSEMS
|
||||
# define DEBUG_RWSEMS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c)
|
||||
@@ -51,14 +55,22 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
|
||||
WRITE_ONCE(sem->owner, RWSEM_READER_OWNED);
|
||||
}
|
||||
|
||||
static inline bool rwsem_owner_is_writer(struct task_struct *owner)
|
||||
/*
|
||||
* Return true if the a rwsem waiter can spin on the rwsem's owner
|
||||
* and steal the lock, i.e. the lock is not anonymously owned.
|
||||
* N.B. !owner is considered spinnable.
|
||||
*/
|
||||
static inline bool is_rwsem_owner_spinnable(struct task_struct *owner)
|
||||
{
|
||||
return owner && owner != RWSEM_READER_OWNED;
|
||||
return !((unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED);
|
||||
}
|
||||
|
||||
static inline bool rwsem_owner_is_reader(struct task_struct *owner)
|
||||
/*
|
||||
* Return true if rwsem is owned by an anonymous writer or readers.
|
||||
*/
|
||||
static inline bool rwsem_has_anonymous_owner(struct task_struct *owner)
|
||||
{
|
||||
return owner == RWSEM_READER_OWNED;
|
||||
return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED;
|
||||
}
|
||||
#else
|
||||
static inline void rwsem_set_owner(struct rw_semaphore *sem)
|
||||
|
@@ -1117,7 +1117,7 @@ extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
|
||||
* should be larger than 2^(64 - 20 - 8), which is more than 64 seconds.
|
||||
* So, overflow is not an issue here.
|
||||
*/
|
||||
u64 grub_reclaim(u64 delta, struct rq *rq, struct sched_dl_entity *dl_se)
|
||||
static u64 grub_reclaim(u64 delta, struct rq *rq, struct sched_dl_entity *dl_se)
|
||||
{
|
||||
u64 u_inact = rq->dl.this_bw - rq->dl.running_bw; /* Utot - Uact */
|
||||
u64 u_act;
|
||||
@@ -2731,8 +2731,6 @@ bool dl_cpu_busy(unsigned int cpu)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_DEBUG
|
||||
extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq);
|
||||
|
||||
void print_dl_stats(struct seq_file *m, int cpu)
|
||||
{
|
||||
print_dl_rq(m, cpu, &cpu_rq(cpu)->dl);
|
||||
|
@@ -2701,8 +2701,6 @@ int sched_rr_handler(struct ctl_table *table, int write,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_DEBUG
|
||||
extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq);
|
||||
|
||||
void print_rt_stats(struct seq_file *m, int cpu)
|
||||
{
|
||||
rt_rq_iter_t iter;
|
||||
|
@@ -2031,8 +2031,9 @@ extern bool sched_debug_enabled;
|
||||
extern void print_cfs_stats(struct seq_file *m, int cpu);
|
||||
extern void print_rt_stats(struct seq_file *m, int cpu);
|
||||
extern void print_dl_stats(struct seq_file *m, int cpu);
|
||||
extern void
|
||||
print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
|
||||
extern void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
|
||||
extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq);
|
||||
extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq);
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
extern void
|
||||
show_numa_stats(struct task_struct *p, struct seq_file *m);
|
||||
|
@@ -1708,7 +1708,7 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rq && sched_debug_enabled) {
|
||||
pr_info("span: %*pbl (max cpu_capacity = %lu)\n",
|
||||
pr_info("root domain span: %*pbl (max cpu_capacity = %lu)\n",
|
||||
cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity);
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/coredump.h>
|
||||
#include <linux/kmemleak.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <linux/seccomp.h>
|
||||
@@ -227,8 +229,11 @@ static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { }
|
||||
|
||||
static inline void seccomp_assign_mode(struct task_struct *task,
|
||||
unsigned long seccomp_mode)
|
||||
unsigned long seccomp_mode,
|
||||
unsigned long flags)
|
||||
{
|
||||
assert_spin_locked(&task->sighand->siglock);
|
||||
|
||||
@@ -238,6 +243,9 @@ static inline void seccomp_assign_mode(struct task_struct *task,
|
||||
* filter) is set.
|
||||
*/
|
||||
smp_mb__before_atomic();
|
||||
/* Assume default seccomp processes want spec flaw mitigation. */
|
||||
if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0)
|
||||
arch_seccomp_spec_mitigate(task);
|
||||
set_tsk_thread_flag(task, TIF_SECCOMP);
|
||||
}
|
||||
|
||||
@@ -305,7 +313,7 @@ static inline pid_t seccomp_can_sync_threads(void)
|
||||
* without dropping the locks.
|
||||
*
|
||||
*/
|
||||
static inline void seccomp_sync_threads(void)
|
||||
static inline void seccomp_sync_threads(unsigned long flags)
|
||||
{
|
||||
struct task_struct *thread, *caller;
|
||||
|
||||
@@ -346,7 +354,8 @@ static inline void seccomp_sync_threads(void)
|
||||
* allow one thread to transition the other.
|
||||
*/
|
||||
if (thread->seccomp.mode == SECCOMP_MODE_DISABLED)
|
||||
seccomp_assign_mode(thread, SECCOMP_MODE_FILTER);
|
||||
seccomp_assign_mode(thread, SECCOMP_MODE_FILTER,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,7 +478,7 @@ static long seccomp_attach_filter(unsigned int flags,
|
||||
|
||||
/* Now that the new filter is in place, synchronize to all threads. */
|
||||
if (flags & SECCOMP_FILTER_FLAG_TSYNC)
|
||||
seccomp_sync_threads();
|
||||
seccomp_sync_threads(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -818,7 +827,7 @@ static long seccomp_set_mode_strict(void)
|
||||
#ifdef TIF_NOTSC
|
||||
disable_TSC();
|
||||
#endif
|
||||
seccomp_assign_mode(current, seccomp_mode);
|
||||
seccomp_assign_mode(current, seccomp_mode, 0);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
@@ -876,7 +885,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
|
||||
/* Do not free the successfully attached filter. */
|
||||
prepared = NULL;
|
||||
|
||||
seccomp_assign_mode(current, seccomp_mode);
|
||||
seccomp_assign_mode(current, seccomp_mode, flags);
|
||||
out:
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
if (flags & SECCOMP_FILTER_FLAG_TSYNC)
|
||||
|
23
kernel/sys.c
23
kernel/sys.c
@@ -61,6 +61,8 @@
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/cred.h>
|
||||
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include <linux/kmsg_dump.h>
|
||||
/* Move somewhere else to avoid recompiling? */
|
||||
#include <generated/utsrelease.h>
|
||||
@@ -2242,6 +2244,17 @@ static int propagate_has_child_subreaper(struct task_struct *p, void *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
|
||||
unsigned long ctrl)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||
unsigned long, arg4, unsigned long, arg5)
|
||||
{
|
||||
@@ -2450,6 +2463,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||
case PR_SVE_GET_VL:
|
||||
error = SVE_GET_VL();
|
||||
break;
|
||||
case PR_GET_SPECULATION_CTRL:
|
||||
if (arg3 || arg4 || arg5)
|
||||
return -EINVAL;
|
||||
error = arch_prctl_spec_ctrl_get(me, arg2);
|
||||
break;
|
||||
case PR_SET_SPECULATION_CTRL:
|
||||
if (arg4 || arg5)
|
||||
return -EINVAL;
|
||||
error = arch_prctl_spec_ctrl_set(me, arg2, arg3);
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
break;
|
||||
|
@@ -612,6 +612,14 @@ static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
|
||||
now = ktime_get();
|
||||
/* Find all expired events */
|
||||
for_each_cpu(cpu, tick_broadcast_oneshot_mask) {
|
||||
/*
|
||||
* Required for !SMP because for_each_cpu() reports
|
||||
* unconditionally CPU0 as set on UP kernels.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_SMP) &&
|
||||
cpumask_empty(tick_broadcast_oneshot_mask))
|
||||
break;
|
||||
|
||||
td = &per_cpu(tick_cpu_device, cpu);
|
||||
if (td->evtdev->next_event <= now) {
|
||||
cpumask_set_cpu(cpu, tmpmask);
|
||||
|
在新工单中引用
屏蔽一个用户