bpf: Right align verifier states in verifier logs.
Make the verifier logs more readable, print the verifier states on the corresponding instruction line. If the previous line was not a bpf instruction, then print the verifier states on its own line. Before: Validating test_pkt_access_subprog3() func#3... 86: R1=invP(id=0) R2=ctx(id=0,off=0,imm=0) R10=fp0 ; int test_pkt_access_subprog3(int val, struct __sk_buff *skb) 86: (bf) r6 = r2 87: R2=ctx(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) 87: (bc) w7 = w1 88: R1=invP(id=0) R7_w=invP(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) ; return get_skb_len(skb) * get_skb_ifindex(val, skb, get_constant(123)); 88: (bf) r1 = r6 89: R1_w=ctx(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) 89: (85) call pc+9 Func#4 is global and valid. Skipping. 90: R0_w=invP(id=0) 90: (bc) w8 = w0 91: R0_w=invP(id=0) R8_w=invP(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) ; return get_skb_len(skb) * get_skb_ifindex(val, skb, get_constant(123)); 91: (b7) r1 = 123 92: R1_w=invP123 92: (85) call pc+65 Func#5 is global and valid. Skipping. 93: R0=invP(id=0) After: 86: R1=invP(id=0) R2=ctx(id=0,off=0,imm=0) R10=fp0 ; int test_pkt_access_subprog3(int val, struct __sk_buff *skb) 86: (bf) r6 = r2 ; R2=ctx(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) 87: (bc) w7 = w1 ; R1=invP(id=0) R7_w=invP(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) ; return get_skb_len(skb) * get_skb_ifindex(val, skb, get_constant(123)); 88: (bf) r1 = r6 ; R1_w=ctx(id=0,off=0,imm=0) R6_w=ctx(id=0,off=0,imm=0) 89: (85) call pc+9 Func#4 is global and valid. Skipping. 90: R0_w=invP(id=0) 90: (bc) w8 = w0 ; R0_w=invP(id=0) R8_w=invP(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) ; return get_skb_len(skb) * get_skb_ifindex(val, skb, get_constant(123)); 91: (b7) r1 = 123 ; R1_w=invP123 92: (85) call pc+65 Func#5 is global and valid. Skipping. 93: R0=invP(id=0) Signed-off-by: Christy Lee <christylee@fb.com> Acked-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0f55f9ed21
commit
2e5766483c
|
@ -388,6 +388,8 @@ static inline bool bpf_verifier_log_full(const struct bpf_verifier_log *log)
|
||||||
#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
|
#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
|
||||||
#define BPF_LOG_MASK (BPF_LOG_LEVEL | BPF_LOG_STATS)
|
#define BPF_LOG_MASK (BPF_LOG_LEVEL | BPF_LOG_STATS)
|
||||||
#define BPF_LOG_KERNEL (BPF_LOG_MASK + 1) /* kernel internal flag */
|
#define BPF_LOG_KERNEL (BPF_LOG_MASK + 1) /* kernel internal flag */
|
||||||
|
#define BPF_LOG_MIN_ALIGNMENT 8U
|
||||||
|
#define BPF_LOG_ALIGNMENT 40U
|
||||||
|
|
||||||
static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
|
static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
|
||||||
{
|
{
|
||||||
|
@ -481,6 +483,7 @@ struct bpf_verifier_env {
|
||||||
u32 scratched_regs;
|
u32 scratched_regs;
|
||||||
/* Same as scratched_regs but for stack slots */
|
/* Same as scratched_regs but for stack slots */
|
||||||
u64 scratched_stack_slots;
|
u64 scratched_stack_slots;
|
||||||
|
u32 prev_log_len, prev_insn_print_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,
|
__printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log,
|
||||||
|
|
|
@ -797,6 +797,25 @@ static void print_verifier_state(struct bpf_verifier_env *env,
|
||||||
mark_verifier_state_clean(env);
|
mark_verifier_state_clean(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 vlog_alignment(u32 pos)
|
||||||
|
{
|
||||||
|
return round_up(max(pos + BPF_LOG_MIN_ALIGNMENT / 2, BPF_LOG_ALIGNMENT),
|
||||||
|
BPF_LOG_MIN_ALIGNMENT) - pos - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_insn_state(struct bpf_verifier_env *env,
|
||||||
|
const struct bpf_func_state *state)
|
||||||
|
{
|
||||||
|
if (env->prev_log_len && env->prev_log_len == env->log.len_used) {
|
||||||
|
/* remove new line character */
|
||||||
|
bpf_vlog_reset(&env->log, env->prev_log_len - 1);
|
||||||
|
verbose(env, "%*c;", vlog_alignment(env->prev_insn_print_len), ' ');
|
||||||
|
} else {
|
||||||
|
verbose(env, "%d:", env->insn_idx);
|
||||||
|
}
|
||||||
|
print_verifier_state(env, state, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* copy array src of length n * size bytes to dst. dst is reallocated if it's too
|
/* copy array src of length n * size bytes to dst. dst is reallocated if it's too
|
||||||
* small to hold src. This is different from krealloc since we don't want to preserve
|
* small to hold src. This is different from krealloc since we don't want to preserve
|
||||||
* the contents of dst.
|
* the contents of dst.
|
||||||
|
@ -2725,10 +2744,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno,
|
||||||
reg->precise = true;
|
reg->precise = true;
|
||||||
}
|
}
|
||||||
if (env->log.level & BPF_LOG_LEVEL) {
|
if (env->log.level & BPF_LOG_LEVEL) {
|
||||||
print_verifier_state(env, func, false);
|
verbose(env, "parent %s regs=%x stack=%llx marks:",
|
||||||
verbose(env, "parent %s regs=%x stack=%llx marks\n",
|
|
||||||
new_marks ? "didn't have" : "already had",
|
new_marks ? "didn't have" : "already had",
|
||||||
reg_mask, stack_mask);
|
reg_mask, stack_mask);
|
||||||
|
print_verifier_state(env, func, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reg_mask && !stack_mask)
|
if (!reg_mask && !stack_mask)
|
||||||
|
@ -3423,11 +3442,8 @@ static int check_mem_region_access(struct bpf_verifier_env *env, u32 regno,
|
||||||
/* We may have adjusted the register pointing to memory region, so we
|
/* We may have adjusted the register pointing to memory region, so we
|
||||||
* need to try adding each of min_value and max_value to off
|
* need to try adding each of min_value and max_value to off
|
||||||
* to make sure our theoretical access will be safe.
|
* to make sure our theoretical access will be safe.
|
||||||
*/
|
*
|
||||||
if (env->log.level & BPF_LOG_LEVEL)
|
* The minimum value is only important with signed
|
||||||
print_verifier_state(env, state, false);
|
|
||||||
|
|
||||||
/* The minimum value is only important with signed
|
|
||||||
* comparisons where we can't assume the floor of a
|
* comparisons where we can't assume the floor of a
|
||||||
* value is 0. If we are using signed variables for our
|
* value is 0. If we are using signed variables for our
|
||||||
* index'es we need to make sure that whatever we use
|
* index'es we need to make sure that whatever we use
|
||||||
|
@ -9438,7 +9454,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
if (env->log.level & BPF_LOG_LEVEL)
|
if (env->log.level & BPF_LOG_LEVEL)
|
||||||
print_verifier_state(env, this_branch->frame[this_branch->curframe], false);
|
print_insn_state(env, this_branch->frame[this_branch->curframe]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11306,19 +11322,12 @@ static int do_check(struct bpf_verifier_env *env)
|
||||||
if (need_resched())
|
if (need_resched())
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
|
||||||
if (env->log.level & BPF_LOG_LEVEL2 ||
|
if (env->log.level & BPF_LOG_LEVEL2 && do_print_state) {
|
||||||
(env->log.level & BPF_LOG_LEVEL && do_print_state)) {
|
verbose(env, "\nfrom %d to %d%s:",
|
||||||
if (env->log.level & BPF_LOG_LEVEL2) {
|
env->prev_insn_idx, env->insn_idx,
|
||||||
if (verifier_state_scratched(env))
|
env->cur_state->speculative ?
|
||||||
verbose(env, "%d:", env->insn_idx);
|
" (speculative execution)" : "");
|
||||||
} else {
|
print_verifier_state(env, state->frame[state->curframe], true);
|
||||||
verbose(env, "\nfrom %d to %d%s:",
|
|
||||||
env->prev_insn_idx, env->insn_idx,
|
|
||||||
env->cur_state->speculative ?
|
|
||||||
" (speculative execution)" : "");
|
|
||||||
}
|
|
||||||
print_verifier_state(env, state->frame[state->curframe],
|
|
||||||
false);
|
|
||||||
do_print_state = false;
|
do_print_state = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11329,9 +11338,15 @@ static int do_check(struct bpf_verifier_env *env)
|
||||||
.private_data = env,
|
.private_data = env,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (verifier_state_scratched(env))
|
||||||
|
print_insn_state(env, state->frame[state->curframe]);
|
||||||
|
|
||||||
verbose_linfo(env, env->insn_idx, "; ");
|
verbose_linfo(env, env->insn_idx, "; ");
|
||||||
|
env->prev_log_len = env->log.len_used;
|
||||||
verbose(env, "%d: ", env->insn_idx);
|
verbose(env, "%d: ", env->insn_idx);
|
||||||
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
|
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
|
||||||
|
env->prev_insn_print_len = env->log.len_used - env->prev_log_len;
|
||||||
|
env->prev_log_len = env->log.len_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bpf_prog_is_dev_bound(env->prog->aux)) {
|
if (bpf_prog_is_dev_bound(env->prog->aux)) {
|
||||||
|
|
|
@ -41,11 +41,11 @@ static struct bpf_align_test tests[] = {
|
||||||
.matches = {
|
.matches = {
|
||||||
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
||||||
{0, "R10=fp0"},
|
{0, "R10=fp0"},
|
||||||
{1, "R3_w=inv2"},
|
{0, "R3_w=inv2"},
|
||||||
{2, "R3_w=inv4"},
|
{1, "R3_w=inv4"},
|
||||||
{3, "R3_w=inv8"},
|
{2, "R3_w=inv8"},
|
||||||
{4, "R3_w=inv16"},
|
{3, "R3_w=inv16"},
|
||||||
{5, "R3_w=inv32"},
|
{4, "R3_w=inv32"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -69,17 +69,17 @@ static struct bpf_align_test tests[] = {
|
||||||
.matches = {
|
.matches = {
|
||||||
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
||||||
{0, "R10=fp0"},
|
{0, "R10=fp0"},
|
||||||
{1, "R3_w=inv1"},
|
{0, "R3_w=inv1"},
|
||||||
{2, "R3_w=inv2"},
|
{1, "R3_w=inv2"},
|
||||||
{3, "R3_w=inv4"},
|
{2, "R3_w=inv4"},
|
||||||
{4, "R3_w=inv8"},
|
{3, "R3_w=inv8"},
|
||||||
{5, "R3_w=inv16"},
|
{4, "R3_w=inv16"},
|
||||||
{6, "R3_w=inv1"},
|
{5, "R3_w=inv1"},
|
||||||
{7, "R4_w=inv32"},
|
{6, "R4_w=inv32"},
|
||||||
{8, "R4_w=inv16"},
|
{7, "R4_w=inv16"},
|
||||||
{9, "R4_w=inv8"},
|
{8, "R4_w=inv8"},
|
||||||
{10, "R4_w=inv4"},
|
{9, "R4_w=inv4"},
|
||||||
{11, "R4_w=inv2"},
|
{10, "R4_w=inv2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -98,12 +98,12 @@ static struct bpf_align_test tests[] = {
|
||||||
.matches = {
|
.matches = {
|
||||||
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
||||||
{0, "R10=fp0"},
|
{0, "R10=fp0"},
|
||||||
{1, "R3_w=inv4"},
|
{0, "R3_w=inv4"},
|
||||||
{2, "R3_w=inv8"},
|
{1, "R3_w=inv8"},
|
||||||
{3, "R3_w=inv10"},
|
{2, "R3_w=inv10"},
|
||||||
{4, "R4_w=inv8"},
|
{3, "R4_w=inv8"},
|
||||||
{5, "R4_w=inv12"},
|
{4, "R4_w=inv12"},
|
||||||
{6, "R4_w=inv14"},
|
{5, "R4_w=inv14"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -120,10 +120,10 @@ static struct bpf_align_test tests[] = {
|
||||||
.matches = {
|
.matches = {
|
||||||
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
{0, "R1=ctx(id=0,off=0,imm=0)"},
|
||||||
{0, "R10=fp0"},
|
{0, "R10=fp0"},
|
||||||
|
{0, "R3_w=inv7"},
|
||||||
{1, "R3_w=inv7"},
|
{1, "R3_w=inv7"},
|
||||||
{2, "R3_w=inv7"},
|
{2, "R3_w=inv14"},
|
||||||
{3, "R3_w=inv14"},
|
{3, "R3_w=inv56"},
|
||||||
{4, "R3_w=inv56"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -162,18 +162,18 @@ static struct bpf_align_test tests[] = {
|
||||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||||
.matches = {
|
.matches = {
|
||||||
{6, "R0_w=pkt(id=0,off=8,r=8,imm=0)"},
|
{6, "R0_w=pkt(id=0,off=8,r=8,imm=0)"},
|
||||||
{7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
{6, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{8, "R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
{7, "R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
||||||
{9, "R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{8, "R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
{10, "R3_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
{9, "R3_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
||||||
{11, "R3_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
{10, "R3_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
||||||
{13, "R3_w=pkt_end(id=0,off=0,imm=0)"},
|
{12, "R3_w=pkt_end(id=0,off=0,imm=0)"},
|
||||||
{18, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
{17, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{19, "R4_w=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0))"},
|
{18, "R4_w=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0))"},
|
||||||
{20, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
{19, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
||||||
{21, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
{20, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
||||||
{22, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{21, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
{23, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
{22, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -194,16 +194,16 @@ static struct bpf_align_test tests[] = {
|
||||||
},
|
},
|
||||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||||
.matches = {
|
.matches = {
|
||||||
{7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
{6, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{8, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
{7, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{9, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
{8, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{10, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
{9, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{11, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
{10, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
|
||||||
{12, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
{11, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{13, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{12, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
{14, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
{13, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
{15, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
{14, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
|
||||||
{16, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
{15, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -234,14 +234,14 @@ static struct bpf_align_test tests[] = {
|
||||||
},
|
},
|
||||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||||
.matches = {
|
.matches = {
|
||||||
{3, "R5_w=pkt(id=0,off=0,r=0,imm=0)"},
|
{2, "R5_w=pkt(id=0,off=0,r=0,imm=0)"},
|
||||||
{5, "R5_w=pkt(id=0,off=14,r=0,imm=0)"},
|
{4, "R5_w=pkt(id=0,off=14,r=0,imm=0)"},
|
||||||
{6, "R4_w=pkt(id=0,off=14,r=0,imm=0)"},
|
{5, "R4_w=pkt(id=0,off=14,r=0,imm=0)"},
|
||||||
{9, "R2=pkt(id=0,off=0,r=18,imm=0)"},
|
{9, "R2=pkt(id=0,off=0,r=18,imm=0)"},
|
||||||
{10, "R5=pkt(id=0,off=14,r=18,imm=0)"},
|
{10, "R5=pkt(id=0,off=14,r=18,imm=0)"},
|
||||||
{10, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
{10, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
|
||||||
|
{13, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
|
||||||
{14, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
|
{14, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
|
||||||
{15, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -297,7 +297,7 @@ static struct bpf_align_test tests[] = {
|
||||||
* alignment of 4.
|
* alignment of 4.
|
||||||
*/
|
*/
|
||||||
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
||||||
{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{7, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Offset is added to packet pointer R5, resulting in
|
/* Offset is added to packet pointer R5, resulting in
|
||||||
* known fixed offset, and variable offset from R6.
|
* known fixed offset, and variable offset from R6.
|
||||||
*/
|
*/
|
||||||
|
@ -313,11 +313,11 @@ static struct bpf_align_test tests[] = {
|
||||||
/* Variable offset is added to R5 packet pointer,
|
/* Variable offset is added to R5 packet pointer,
|
||||||
* resulting in auxiliary alignment of 4.
|
* resulting in auxiliary alignment of 4.
|
||||||
*/
|
*/
|
||||||
{18, "R5_w=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{17, "R5_w=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Constant offset is added to R5, resulting in
|
/* Constant offset is added to R5, resulting in
|
||||||
* reg->off of 14.
|
* reg->off of 14.
|
||||||
*/
|
*/
|
||||||
{19, "R5_w=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{18, "R5_w=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off
|
* its total fixed offset is NET_IP_ALIGN + reg->off
|
||||||
* (14) which is 16. Then the variable offset is 4-byte
|
* (14) which is 16. Then the variable offset is 4-byte
|
||||||
|
@ -329,18 +329,18 @@ static struct bpf_align_test tests[] = {
|
||||||
/* Constant offset is added to R5 packet pointer,
|
/* Constant offset is added to R5 packet pointer,
|
||||||
* resulting in reg->off value of 14.
|
* resulting in reg->off value of 14.
|
||||||
*/
|
*/
|
||||||
{26, "R5_w=pkt(id=0,off=14,r=8"},
|
{25, "R5_w=pkt(id=0,off=14,r=8"},
|
||||||
/* Variable offset is added to R5, resulting in a
|
/* Variable offset is added to R5, resulting in a
|
||||||
* variable offset of (4n).
|
* variable offset of (4n).
|
||||||
*/
|
*/
|
||||||
{27, "R5_w=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{26, "R5_w=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Constant is added to R5 again, setting reg->off to 18. */
|
/* Constant is added to R5 again, setting reg->off to 18. */
|
||||||
{28, "R5_w=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{27, "R5_w=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* And once more we add a variable; resulting var_off
|
/* And once more we add a variable; resulting var_off
|
||||||
* is still (4n), fixed offset is not changed.
|
* is still (4n), fixed offset is not changed.
|
||||||
* Also, we create a new reg->id.
|
* Also, we create a new reg->id.
|
||||||
*/
|
*/
|
||||||
{29, "R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc)"},
|
{28, "R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc)"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off (18)
|
* its total fixed offset is NET_IP_ALIGN + reg->off (18)
|
||||||
* which is 20. Then the variable offset is (4n), so
|
* which is 20. Then the variable offset is (4n), so
|
||||||
|
@ -387,12 +387,12 @@ static struct bpf_align_test tests[] = {
|
||||||
* alignment of 4.
|
* alignment of 4.
|
||||||
*/
|
*/
|
||||||
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
||||||
{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{7, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Adding 14 makes R6 be (4n+2) */
|
/* Adding 14 makes R6 be (4n+2) */
|
||||||
{9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
{8, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
||||||
/* Packet pointer has (4n+2) offset */
|
/* Packet pointer has (4n+2) offset */
|
||||||
{11, "R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
|
{11, "R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
|
||||||
{13, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
|
{12, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
||||||
* which is 2. Then the variable offset is (4n+2), so
|
* which is 2. Then the variable offset is (4n+2), so
|
||||||
|
@ -403,12 +403,12 @@ static struct bpf_align_test tests[] = {
|
||||||
/* Newly read value in R6 was shifted left by 2, so has
|
/* Newly read value in R6 was shifted left by 2, so has
|
||||||
* known alignment of 4.
|
* known alignment of 4.
|
||||||
*/
|
*/
|
||||||
{18, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{17, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Added (4n) to packet pointer's (4n+2) var_off, giving
|
/* Added (4n) to packet pointer's (4n+2) var_off, giving
|
||||||
* another (4n+2).
|
* another (4n+2).
|
||||||
*/
|
*/
|
||||||
{19, "R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
|
{19, "R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
|
||||||
{21, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
|
{20, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
||||||
* which is 2. Then the variable offset is (4n+2), so
|
* which is 2. Then the variable offset is (4n+2), so
|
||||||
|
@ -448,18 +448,18 @@ static struct bpf_align_test tests[] = {
|
||||||
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
|
||||||
.result = REJECT,
|
.result = REJECT,
|
||||||
.matches = {
|
.matches = {
|
||||||
{4, "R5_w=pkt_end(id=0,off=0,imm=0)"},
|
{3, "R5_w=pkt_end(id=0,off=0,imm=0)"},
|
||||||
/* (ptr - ptr) << 2 == unknown, (4n) */
|
/* (ptr - ptr) << 2 == unknown, (4n) */
|
||||||
{6, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc)"},
|
{5, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc)"},
|
||||||
/* (4n) + 14 == (4n+2). We blow our bounds, because
|
/* (4n) + 14 == (4n+2). We blow our bounds, because
|
||||||
* the add could overflow.
|
* the add could overflow.
|
||||||
*/
|
*/
|
||||||
{7, "R5_w=inv(id=0,smin_value=-9223372036854775806,smax_value=9223372036854775806,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
|
{6, "R5_w=inv(id=0,smin_value=-9223372036854775806,smax_value=9223372036854775806,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
|
||||||
/* Checked s>=0 */
|
/* Checked s>=0 */
|
||||||
{9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
{9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
||||||
/* packet pointer + nonnegative (4n+2) */
|
/* packet pointer + nonnegative (4n+2) */
|
||||||
{12, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
{11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
||||||
{13, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
{12, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
|
||||||
/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
|
/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
|
||||||
* We checked the bounds, but it might have been able
|
* We checked the bounds, but it might have been able
|
||||||
* to overflow if the packet pointer started in the
|
* to overflow if the packet pointer started in the
|
||||||
|
@ -502,14 +502,14 @@ static struct bpf_align_test tests[] = {
|
||||||
/* Calculated offset in R6 has unknown value, but known
|
/* Calculated offset in R6 has unknown value, but known
|
||||||
* alignment of 4.
|
* alignment of 4.
|
||||||
*/
|
*/
|
||||||
{7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
||||||
{9, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Adding 14 makes R6 be (4n+2) */
|
/* Adding 14 makes R6 be (4n+2) */
|
||||||
{10, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
{9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
||||||
/* New unknown value in R7 is (4n) */
|
/* New unknown value in R7 is (4n) */
|
||||||
{11, "R7_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
{10, "R7_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
|
||||||
/* Subtracting it from R6 blows our unsigned bounds */
|
/* Subtracting it from R6 blows our unsigned bounds */
|
||||||
{12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
|
{11, "R6=inv(id=0,smin_value=-1006,smax_value=1034,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
|
||||||
/* Checked s>= 0 */
|
/* Checked s>= 0 */
|
||||||
{14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
{14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
|
@ -556,14 +556,14 @@ static struct bpf_align_test tests[] = {
|
||||||
/* Calculated offset in R6 has unknown value, but known
|
/* Calculated offset in R6 has unknown value, but known
|
||||||
* alignment of 4.
|
* alignment of 4.
|
||||||
*/
|
*/
|
||||||
{7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
{6, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
|
||||||
{10, "R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"},
|
{9, "R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"},
|
||||||
/* Adding 14 makes R6 be (4n+2) */
|
/* Adding 14 makes R6 be (4n+2) */
|
||||||
{11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},
|
{10, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},
|
||||||
/* Subtracting from packet pointer overflows ubounds */
|
/* Subtracting from packet pointer overflows ubounds */
|
||||||
{13, "R5_w=pkt(id=2,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},
|
{13, "R5_w=pkt(id=2,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},
|
||||||
/* New unknown value in R7 is (4n), >= 76 */
|
/* New unknown value in R7 is (4n), >= 76 */
|
||||||
{15, "R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"},
|
{14, "R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"},
|
||||||
/* Adding it to packet pointer gives nice bounds again */
|
/* Adding it to packet pointer gives nice bounds again */
|
||||||
{16, "R5_w=pkt(id=3,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
|
{16, "R5_w=pkt(id=3,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
|
@ -625,12 +625,15 @@ static int do_test_single(struct bpf_align_test *test)
|
||||||
line_ptr = strtok(bpf_vlog_copy, "\n");
|
line_ptr = strtok(bpf_vlog_copy, "\n");
|
||||||
for (i = 0; i < MAX_MATCHES; i++) {
|
for (i = 0; i < MAX_MATCHES; i++) {
|
||||||
struct bpf_reg_match m = test->matches[i];
|
struct bpf_reg_match m = test->matches[i];
|
||||||
|
int tmp;
|
||||||
|
|
||||||
if (!m.match)
|
if (!m.match)
|
||||||
break;
|
break;
|
||||||
while (line_ptr) {
|
while (line_ptr) {
|
||||||
cur_line = -1;
|
cur_line = -1;
|
||||||
sscanf(line_ptr, "%u: ", &cur_line);
|
sscanf(line_ptr, "%u: ", &cur_line);
|
||||||
|
if (cur_line == -1)
|
||||||
|
sscanf(line_ptr, "from %u to %u: ", &tmp, &cur_line);
|
||||||
if (cur_line == m.line)
|
if (cur_line == m.line)
|
||||||
break;
|
break;
|
||||||
line_ptr = strtok(NULL, "\n");
|
line_ptr = strtok(NULL, "\n");
|
||||||
|
@ -642,7 +645,19 @@ static int do_test_single(struct bpf_align_test *test)
|
||||||
printf("%s", bpf_vlog);
|
printf("%s", bpf_vlog);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Check the next line as well in case the previous line
|
||||||
|
* did not have a corresponding bpf insn. Example:
|
||||||
|
* func#0 @0
|
||||||
|
* 0: R1=ctx(id=0,off=0,imm=0) R10=fp0
|
||||||
|
* 0: (b7) r3 = 2 ; R3_w=inv2
|
||||||
|
*/
|
||||||
if (!strstr(line_ptr, m.match)) {
|
if (!strstr(line_ptr, m.match)) {
|
||||||
|
cur_line = -1;
|
||||||
|
line_ptr = strtok(NULL, "\n");
|
||||||
|
sscanf(line_ptr, "%u: ", &cur_line);
|
||||||
|
}
|
||||||
|
if (cur_line != m.line || !line_ptr ||
|
||||||
|
!strstr(line_ptr, m.match)) {
|
||||||
printf("Failed to find match %u: %s\n",
|
printf("Failed to find match %u: %s\n",
|
||||||
m.line, m.match);
|
m.line, m.match);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
Loading…
Reference in New Issue