Skip to content

Commit b1de265

Browse files
shiloongmaqiao-mq
authored andcommitted
Revert "bpf: Fix leakage due to insufficient speculative store bypass mitigation"
ANBZ: torvalds#342 This reverts commit 6e458fd. Signed-off-by: Qiao Ma <[email protected]> Acked-by: Mao Wenan <[email protected]> Acked-by: Tony Lu <[email protected]>
1 parent b7eff59 commit b1de265

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

include/linux/bpf_verifier.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ struct bpf_insn_aux_data {
158158
u32 alu_limit; /* limit for add/sub register with pointer */
159159
};
160160
int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
161+
int sanitize_stack_off; /* stack slot to be cleared */
161162
bool seen; /* this insn was processed by the verifier */
162-
bool sanitize_stack_spill; /* subject to Spectre v4 sanitation */
163163
u8 alu_state; /* used in combination with alu_limit */
164164
};
165165

kernel/bpf/verifier.c

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,19 +1009,6 @@ static int check_stack_write(struct bpf_verifier_env *env,
10091009
cur = env->cur_state->frame[env->cur_state->curframe];
10101010
if (value_regno >= 0)
10111011
reg = &cur->regs[value_regno];
1012-
if (!env->allow_ptr_leaks) {
1013-
bool sanitize = reg && is_spillable_regtype(reg->type);
1014-
1015-
for (i = 0; i < size; i++) {
1016-
if (state->stack[spi].slot_type[i] == STACK_INVALID) {
1017-
sanitize = true;
1018-
break;
1019-
}
1020-
}
1021-
1022-
if (sanitize)
1023-
env->insn_aux_data[insn_idx].sanitize_stack_spill = true;
1024-
}
10251012

10261013
if (reg && size == BPF_REG_SIZE && register_is_const(reg) &&
10271014
!register_is_null(reg) && env->allow_ptr_leaks) {
@@ -1032,10 +1019,47 @@ static int check_stack_write(struct bpf_verifier_env *env,
10321019
verbose(env, "invalid size of register spill\n");
10331020
return -EACCES;
10341021
}
1022+
10351023
if (state != cur && reg->type == PTR_TO_STACK) {
10361024
verbose(env, "cannot spill pointers to stack into stack frame of the caller\n");
10371025
return -EINVAL;
10381026
}
1027+
1028+
if (!env->allow_ptr_leaks) {
1029+
bool sanitize = false;
1030+
1031+
if (state->stack[spi].slot_type[0] == STACK_SPILL &&
1032+
register_is_const(&state->stack[spi].spilled_ptr))
1033+
sanitize = true;
1034+
for (i = 0; i < BPF_REG_SIZE; i++)
1035+
if (state->stack[spi].slot_type[i] == STACK_MISC) {
1036+
sanitize = true;
1037+
break;
1038+
}
1039+
if (sanitize) {
1040+
int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off;
1041+
int soff = (-spi - 1) * BPF_REG_SIZE;
1042+
1043+
/* detected reuse of integer stack slot with a pointer
1044+
* which means either llvm is reusing stack slot or
1045+
* an attacker is trying to exploit CVE-2018-3639
1046+
* (speculative store bypass)
1047+
* Have to sanitize that slot with preemptive
1048+
* store of zero.
1049+
*/
1050+
if (*poff && *poff != soff) {
1051+
/* disallow programs where single insn stores
1052+
* into two different stack slots, since verifier
1053+
* cannot sanitize them
1054+
*/
1055+
verbose(env,
1056+
"insn %d cannot access two stack slots fp%d and fp%d",
1057+
insn_idx, *poff, soff);
1058+
return -EINVAL;
1059+
}
1060+
*poff = soff;
1061+
}
1062+
}
10391063
save_register_state(state, spi, reg);
10401064
} else {
10411065
u8 type = STACK_MISC;
@@ -5808,33 +5832,34 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
58085832
insn = env->prog->insnsi + delta;
58095833

58105834
for (i = 0; i < insn_cnt; i++, insn++) {
5811-
bool ctx_access;
5812-
58135835
if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) ||
58145836
insn->code == (BPF_LDX | BPF_MEM | BPF_H) ||
58155837
insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
5816-
insn->code == (BPF_LDX | BPF_MEM | BPF_DW)) {
5838+
insn->code == (BPF_LDX | BPF_MEM | BPF_DW))
58175839
type = BPF_READ;
5818-
ctx_access = true;
5819-
} else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) ||
5820-
insn->code == (BPF_STX | BPF_MEM | BPF_H) ||
5821-
insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
5822-
insn->code == (BPF_STX | BPF_MEM | BPF_DW) ||
5823-
insn->code == (BPF_ST | BPF_MEM | BPF_B) ||
5824-
insn->code == (BPF_ST | BPF_MEM | BPF_H) ||
5825-
insn->code == (BPF_ST | BPF_MEM | BPF_W) ||
5826-
insn->code == (BPF_ST | BPF_MEM | BPF_DW)) {
5840+
else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) ||
5841+
insn->code == (BPF_STX | BPF_MEM | BPF_H) ||
5842+
insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
5843+
insn->code == (BPF_STX | BPF_MEM | BPF_DW))
58275844
type = BPF_WRITE;
5828-
ctx_access = BPF_CLASS(insn->code) == BPF_STX;
5829-
} else {
5845+
else
58305846
continue;
5831-
}
58325847

58335848
if (type == BPF_WRITE &&
5834-
env->insn_aux_data[i + delta].sanitize_stack_spill) {
5849+
env->insn_aux_data[i + delta].sanitize_stack_off) {
58355850
struct bpf_insn patch[] = {
5851+
/* Sanitize suspicious stack slot with zero.
5852+
* There are no memory dependencies for this store,
5853+
* since it's only using frame pointer and immediate
5854+
* constant of zero
5855+
*/
5856+
BPF_ST_MEM(BPF_DW, BPF_REG_FP,
5857+
env->insn_aux_data[i + delta].sanitize_stack_off,
5858+
0),
5859+
/* the original STX instruction will immediately
5860+
* overwrite the same stack slot with appropriate value
5861+
*/
58365862
*insn,
5837-
BPF_ST_NOSPEC(),
58385863
};
58395864

58405865
cnt = ARRAY_SIZE(patch);
@@ -5848,9 +5873,6 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
58485873
continue;
58495874
}
58505875

5851-
if (!ctx_access)
5852-
continue;
5853-
58545876
if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
58555877
continue;
58565878

0 commit comments

Comments
 (0)