Merge branch 'speck-v20' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Merge speculative store buffer bypass fixes from Thomas Gleixner: - rework of the SPEC_CTRL MSR management to accomodate the new fancy SSBD (Speculative Store Bypass Disable) bit handling. - the CPU bug and sysfs infrastructure for the exciting new Speculative Store Bypass 'feature'. - support for disabling SSB via LS_CFG MSR on AMD CPUs including Hyperthread synchronization on ZEN. - PRCTL support for dynamic runtime control of SSB - SECCOMP integration to automatically disable SSB for sandboxed processes with a filter flag for opt-out. - KVM integration to allow guests fiddling with SSBD including the new software MSR VIRT_SPEC_CTRL to handle the LS_CFG based oddities on AMD. - BPF protection against SSB .. this is just the core and x86 side, other architecture support will come separately. * 'speck-v20' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (49 commits) bpf: Prevent memory disambiguation attack x86/bugs: Rename SSBD_NO to SSB_NO KVM: SVM: Implement VIRT_SPEC_CTRL support for SSBD x86/speculation, KVM: Implement support for VIRT_SPEC_CTRL/LS_CFG x86/bugs: Rework spec_ctrl base and mask logic x86/bugs: Remove x86_spec_ctrl_set() x86/bugs: Expose x86_spec_ctrl_base directly x86/bugs: Unify x86_spec_ctrl_{set_guest,restore_host} x86/speculation: Rework speculative_store_bypass_update() x86/speculation: Add virtualized speculative store bypass disable support x86/bugs, KVM: Extend speculation control for VIRT_SPEC_CTRL x86/speculation: Handle HT correctly on AMD x86/cpufeatures: Add FEATURE_ZEN x86/cpufeatures: Disentangle SSBD enumeration x86/cpufeatures: Disentangle MSR_SPEC_CTRL enumeration from IBRS x86/speculation: Use synthetic bits for IBRS/IBPB/STIBP KVM: SVM: Move spec control call after restore of GS x86/cpu: Make alternative_msr_write work for 32-bit code x86/bugs: Fix the parameters alignment and missing void x86/bugs: Make cpu_show_common() static ...
This commit is contained in:
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user