Skip to content

Commit d1427b7

Browse files
committed
bpf: Clarify sanitize_check_bounds()
As is, it appears as if ptr alu is allowed for everything except PTR_TO_{STACK,MAP_VALUE} if one only reads sanitize_check_bounds(). However, this is misleading as it only works together with retrieve_ptr_limit() and the two must be kept in sync. This patch documents the interdependency and adds a check to ensure they stay in sync. Because the preceeding switch returns -EACCES for every opcode except for ADD/SUB, the sanitize_needed() following the sanitize_check_bounds() call is always true if reached. This means, unless sanitize_check_bounds() detected that the pointer goes OOB because of the ADD/SUB (and returns -EACCES), sanitize_ptr_alu() always executes after sanitize_check_bounds(). In sanitize_ptr_alu(commit_window = true), we always run retrieve_ptr_limit() unless: * can_skip_alu_sanititation() is true, i.e., noteably `BPF_SRC(insn->code) == BPF_K`. BPF_K is fine because it means that there is no scalar register (which could be subject to spec. scalar confusion due to v4) that goes into the alu op. The ptr reg can not be subject to v4-based value confusion due to the nospec added. * We are on a speculative path (`vstate->speculative`). This is because there are no alu sanitization limits to be learned from speculative paths. retrieve_ptr_limit() only allows the ALU op if the involved ptr reg (can be either rhs or lhs for ADD) is PTR_TO_STACK or PTR_TO_MAP_VALUE. Otherwise it returns -EOPNOTSUPP. In summary, sanitize_check_bounds() returning 0 for non-PTR_TO_{STACK,MAP_VALUE} is fine because retrieve_ptr_limit() still prevents the unsafe ops. We allow unsanitized ptr arith with ADD/SUB for * ptr -=/+= imm32, i.e. `BPF_SRC(insn->code) == BPF_K` * PTR_TO_{STACK,MAP_VALUE} -= scalar * PTR_TO_{STACK,MAP_VALUE} += scalar * scalar += PTR_TO_{STACK,MAP_VALUE} if the requirements from retrieve_ptr_limit() AND sanitize_check_bounds() hold. To document this interdependency and ensure they stay in sync, add a verifier_bug_if(). Signed-off-by: Luis Gerhorst <[email protected]>
1 parent 5ead949 commit d1427b7

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

kernel/bpf/verifier.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14297,7 +14297,7 @@ static int sanitize_check_bounds(struct bpf_verifier_env *env,
1429714297
}
1429814298
break;
1429914299
default:
14300-
break;
14300+
return -EOPNOTSUPP;
1430114301
}
1430214302

1430314303
return 0;
@@ -14324,7 +14324,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1432414324
struct bpf_sanitize_info info = {};
1432514325
u8 opcode = BPF_OP(insn->code);
1432614326
u32 dst = insn->dst_reg;
14327-
int ret;
14327+
int ret, bounds_ret;
1432814328

1432914329
dst_reg = &regs[dst];
1433014330

@@ -14524,11 +14524,17 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1452414524
if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
1452514525
return -EINVAL;
1452614526
reg_bounds_sync(dst_reg);
14527-
if (sanitize_check_bounds(env, insn, dst_reg) < 0)
14528-
return -EACCES;
14527+
bounds_ret = sanitize_check_bounds(env, insn, dst_reg);
14528+
if (bounds_ret == -EACCES)
14529+
return bounds_ret;
1452914530
if (sanitize_needed(opcode)) {
1453014531
ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
1453114532
&info, true);
14533+
if (!can_skip_alu_sanitation(env, insn) &&
14534+
verifier_bug_if(bounds_ret == -EOPNOTSUPP && !ret,
14535+
env, "Pointer type unsupported by sanitize_check_bounds() not rejected by retrieve_ptr_limit() as required")) {
14536+
return -EFAULT;
14537+
}
1453214538
if (ret < 0)
1453314539
return sanitize_err(env, insn, ret, off_reg, dst_reg);
1453414540
}

0 commit comments

Comments
 (0)