bpf: Prevent memory disambiguation attack

Detect code patterns where malicious 'speculative store bypass' can be used
and sanitize such patterns.

39: (bf) r3 = r10
40: (07) r3 += -216
41: (79) r8 = *(u64 *)(r7 +0) // slow read
42: (7a) *(u64 *)(r10 -72) = 0 // verifier inserts this instruction
43: (7b) *(u64 *)(r8 +0) = r3 // this store becomes slow due to r8
44: (79) r1 = *(u64 *)(r6 +0) // cpu speculatively executes this load
45: (71) r2 = *(u8 *)(r1 +0) // speculatively arbitrary 'load byte'
// is now sanitized

Above code after x86 JIT becomes:
e5: mov %rbp,%rdx
e8: add $0xffffffffffffff28,%rdx
ef: mov 0x0(%r13),%r14
f3: movq $0x0,-0x48(%rbp)
fb: mov %rdx,0x0(%r14)
ff: mov 0x0(%rbx),%rdi
103: movzbq 0x0(%rdi),%rsi

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by Alexei Starovoitov and committed by Thomas Gleixner af86ca4e 240da953

+57 -3
+1
include/linux/bpf_verifier.h
··· 146 146 s32 call_imm; /* saved imm field of call insn */ 147 147 }; 148 148 int ctx_field_size; /* the ctx field size for load insn, maybe 0 */ 149 + int sanitize_stack_off; /* stack slot to be cleared */ 149 150 bool seen; /* this insn was processed by the verifier */ 150 151 }; 151 152
+56 -3
kernel/bpf/verifier.c
··· 978 978 */ 979 979 static int check_stack_write(struct bpf_verifier_env *env, 980 980 struct bpf_func_state *state, /* func where register points to */ 981 - int off, int size, int value_regno) 981 + int off, int size, int value_regno, int insn_idx) 982 982 { 983 983 struct bpf_func_state *cur; /* state of the current function */ 984 984 int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err; ··· 1017 1017 state->stack[spi].spilled_ptr = cur->regs[value_regno]; 1018 1018 state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 1019 1019 1020 - for (i = 0; i < BPF_REG_SIZE; i++) 1020 + for (i = 0; i < BPF_REG_SIZE; i++) { 1021 + if (state->stack[spi].slot_type[i] == STACK_MISC && 1022 + !env->allow_ptr_leaks) { 1023 + int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off; 1024 + int soff = (-spi - 1) * BPF_REG_SIZE; 1025 + 1026 + /* detected reuse of integer stack slot with a pointer 1027 + * which means either llvm is reusing stack slot or 1028 + * an attacker is trying to exploit CVE-2018-3639 1029 + * (speculative store bypass) 1030 + * Have to sanitize that slot with preemptive 1031 + * store of zero. 1032 + */ 1033 + if (*poff && *poff != soff) { 1034 + /* disallow programs where single insn stores 1035 + * into two different stack slots, since verifier 1036 + * cannot sanitize them 1037 + */ 1038 + verbose(env, 1039 + "insn %d cannot access two stack slots fp%d and fp%d", 1040 + insn_idx, *poff, soff); 1041 + return -EINVAL; 1042 + } 1043 + *poff = soff; 1044 + } 1021 1045 state->stack[spi].slot_type[i] = STACK_SPILL; 1046 + } 1022 1047 } else { 1023 1048 u8 type = STACK_MISC; 1024 1049 ··· 1719 1694 1720 1695 if (t == BPF_WRITE) 1721 1696 err = check_stack_write(env, state, off, size, 1722 - value_regno); 1697 + value_regno, insn_idx); 1723 1698 else 1724 1699 err = check_stack_read(env, state, off, size, 1725 1700 value_regno); ··· 5193 5168 type = BPF_WRITE; 5194 5169 else 5195 5170 continue; 5171 + 5172 + if (type == BPF_WRITE && 5173 + env->insn_aux_data[i + delta].sanitize_stack_off) { 5174 + struct bpf_insn patch[] = { 5175 + /* Sanitize suspicious stack slot with zero. 5176 + * There are no memory dependencies for this store, 5177 + * since it's only using frame pointer and immediate 5178 + * constant of zero 5179 + */ 5180 + BPF_ST_MEM(BPF_DW, BPF_REG_FP, 5181 + env->insn_aux_data[i + delta].sanitize_stack_off, 5182 + 0), 5183 + /* the original STX instruction will immediately 5184 + * overwrite the same stack slot with appropriate value 5185 + */ 5186 + *insn, 5187 + }; 5188 + 5189 + cnt = ARRAY_SIZE(patch); 5190 + new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt); 5191 + if (!new_prog) 5192 + return -ENOMEM; 5193 + 5194 + delta += cnt - 1; 5195 + env->prog = new_prog; 5196 + insn = new_prog->insnsi + i + delta; 5197 + continue; 5198 + } 5196 5199 5197 5200 if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX) 5198 5201 continue;