Skip to content

Commit be561c0

Browse files
borkmanngregkh
authored andcommitted
bpf: Fix pointer arithmetic mask tightening under state pruning
commit e042aa5 upstream. In 7fedb63 ("bpf: Tighten speculative pointer arithmetic mask") we narrowed the offset mask for unprivileged pointer arithmetic in order to mitigate a corner case where in the speculative domain it is possible to advance, for example, the map value pointer by up to value_size-1 out-of- bounds in order to leak kernel memory via side-channel to user space. The verifier's state pruning for scalars leaves one corner case open where in the first verification path R_x holds an unknown scalar with an aux->alu_limit of e.g. 7, and in a second verification path that same register R_x, here denoted as R_x', holds an unknown scalar which has tighter bounds and would thus satisfy range_within(R_x, R_x') as well as tnum_in(R_x, R_x') for state pruning, yielding an aux->alu_limit of 3: Given the second path fits the register constraints for pruning, the final generated mask from aux->alu_limit will remain at 7. While technically not wrong for the non-speculative domain, it would however be possible to craft similar cases where the mask would be too wide as in 7fedb63. One way to fix it is to detect the presence of unknown scalar map pointer arithmetic and force a deeper search on unknown scalars to ensure that we do not run into a masking mismatch. Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ffb9d5c commit be561c0

File tree

2 files changed

+18
-10
lines changed

2 files changed

+18
-10
lines changed

include/linux/bpf_verifier.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ struct bpf_verifier_env {
397397
struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
398398
u32 used_map_cnt; /* number of used maps */
399399
u32 id_gen; /* used to generate unique reg IDs */
400+
bool explore_alu_limits;
400401
bool allow_ptr_leaks;
401402
bool allow_uninit_stack;
402403
bool allow_ptr_to_map_access;

kernel/bpf/verifier.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5792,6 +5792,12 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
57925792
alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0;
57935793
alu_state |= ptr_is_dst_reg ?
57945794
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
5795+
5796+
/* Limit pruning on unknown scalars to enable deep search for
5797+
* potential masking differences from other program paths.
5798+
*/
5799+
if (!off_is_imm)
5800+
env->explore_alu_limits = true;
57955801
}
57965802

57975803
err = update_alu_sanitation_state(aux, alu_state, alu_limit);
@@ -9088,8 +9094,8 @@ static void clean_live_states(struct bpf_verifier_env *env, int insn,
90889094
}
90899095

90909096
/* Returns true if (rold safe implies rcur safe) */
9091-
static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
9092-
struct bpf_id_pair *idmap)
9097+
static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold,
9098+
struct bpf_reg_state *rcur, struct bpf_id_pair *idmap)
90939099
{
90949100
bool equal;
90959101

@@ -9115,6 +9121,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
91159121
return false;
91169122
switch (rold->type) {
91179123
case SCALAR_VALUE:
9124+
if (env->explore_alu_limits)
9125+
return false;
91189126
if (rcur->type == SCALAR_VALUE) {
91199127
if (!rold->precise && !rcur->precise)
91209128
return true;
@@ -9204,9 +9212,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
92049212
return false;
92059213
}
92069214

9207-
static bool stacksafe(struct bpf_func_state *old,
9208-
struct bpf_func_state *cur,
9209-
struct bpf_id_pair *idmap)
9215+
static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old,
9216+
struct bpf_func_state *cur, struct bpf_id_pair *idmap)
92109217
{
92119218
int i, spi;
92129219

@@ -9251,9 +9258,8 @@ static bool stacksafe(struct bpf_func_state *old,
92519258
continue;
92529259
if (old->stack[spi].slot_type[0] != STACK_SPILL)
92539260
continue;
9254-
if (!regsafe(&old->stack[spi].spilled_ptr,
9255-
&cur->stack[spi].spilled_ptr,
9256-
idmap))
9261+
if (!regsafe(env, &old->stack[spi].spilled_ptr,
9262+
&cur->stack[spi].spilled_ptr, idmap))
92579263
/* when explored and current stack slot are both storing
92589264
* spilled registers, check that stored pointers types
92599265
* are the same as well.
@@ -9310,10 +9316,11 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat
93109316

93119317
memset(env->idmap_scratch, 0, sizeof(env->idmap_scratch));
93129318
for (i = 0; i < MAX_BPF_REG; i++)
9313-
if (!regsafe(&old->regs[i], &cur->regs[i], env->idmap_scratch))
9319+
if (!regsafe(env, &old->regs[i], &cur->regs[i],
9320+
env->idmap_scratch))
93149321
return false;
93159322

9316-
if (!stacksafe(old, cur, env->idmap_scratch))
9323+
if (!stacksafe(env, old, cur, env->idmap_scratch))
93179324
return false;
93189325

93199326
if (!refsafe(old, cur))

0 commit comments

Comments
 (0)