History

bpf: Don't predict JMP32 pointer vs zero comparisons

Consider the following program: r1 = map_value; /* low 32 bits are zero at runtime */ r6 = 0xdead000000000000; if w1 != 0 goto l1; l0: r1 += r6; r2 = *(u64 *)(r1 + 0); exit; l1: r6 = 0; goto l0; At the moment is_branch_taken() reports the jump as always taken, because it does not distinguish between BPF_JMP and BPF_JMP32 comparisons when processing 'if w1 != 0 ...'.

Eduard Zingerman committed 2 months ago

Commit e51179a1 parent bc412b31 file · +7 −0Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/bpf/verifier.c+7−0
@@ -16337,6 +16337,13 @@ static int is_branch_taken(struct bpf_verifier_env *env, struct bpf_reg_state *r · 16336 unmodified lines
16337 if (__is_pointer_value(false, reg1) || __is_pointer_value(false, reg2)) {16337 if (__is_pointer_value(false, reg1) || __is_pointer_value(false, reg2)) {
16338 u64 val;16338 u64 val;
16339 16339
16340 /*
16341 * The low 32 bits of a valid pointer may well be zero, hence
16342 * nothing below applies to a 32-bit comparison.
16343 */
16344 if (is_jmp32)
16345 return -1;
16346
16340 /* arrange that reg2 is a scalar, and reg1 is a pointer */16347 /* arrange that reg2 is a scalar, and reg1 is a pointer */
16341 if (!is_reg_const(reg2, is_jmp32)) {16348 if (!is_reg_const(reg2, is_jmp32)) {
16342 opcode = flip_opcode(opcode);16349 opcode = flip_opcode(opcode);