bpf: emit frameno for PTR_TO_STACK regs if it differs from current one

It's possible to pass a pointer to parent's stack to child subprogs. In
such case verifier state output is ambiguous not showing whether
register container a pointer to "current" stack, belonging to current
subprog (frame), or it's actually a pointer to one of parent frames.

So emit this information if frame number differs between the state which
register is part of. E.g., if current state is in frame 2 and it has
a register pointing to stack in grand parent state (frame #0), we'll see
something like 'R1=fp[0]-16', while "local stack pointer" will be just
'R2=fp-16'.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231118034623.3320920-9-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Andrii Nakryiko 2023-11-17 19:46:23 -08:00 committed by Alexei Starovoitov
parent 0f8dbdbc64
commit 46862ee854

View File

@ -615,7 +615,9 @@ static bool type_is_map_ptr(enum bpf_reg_type t) {
} }
} }
static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_state *reg) static void print_reg_state(struct bpf_verifier_env *env,
const struct bpf_func_state *state,
const struct bpf_reg_state *reg)
{ {
enum bpf_reg_type t; enum bpf_reg_type t;
const char *sep = ""; const char *sep = "";
@ -623,10 +625,8 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s
t = reg->type; t = reg->type;
if (t == SCALAR_VALUE && reg->precise) if (t == SCALAR_VALUE && reg->precise)
verbose(env, "P"); verbose(env, "P");
if ((t == SCALAR_VALUE || t == PTR_TO_STACK) && if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) {
tnum_is_const(reg->var_off)) {
/* reg->off should be 0 for SCALAR_VALUE */ /* reg->off should be 0 for SCALAR_VALUE */
verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t));
verbose_snum(env, reg->var_off.value + reg->off); verbose_snum(env, reg->var_off.value + reg->off);
return; return;
} }
@ -637,6 +637,14 @@ static void print_reg_state(struct bpf_verifier_env *env, const struct bpf_reg_s
#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, ##__VA_ARGS__); sep = ","; }) #define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, ##__VA_ARGS__); sep = ","; })
verbose(env, "%s", reg_type_str(env, t)); verbose(env, "%s", reg_type_str(env, t));
if (t == PTR_TO_STACK) {
if (state->frameno != reg->frameno)
verbose(env, "[%d]", reg->frameno);
if (tnum_is_const(reg->var_off)) {
verbose_snum(env, reg->var_off.value + reg->off);
return;
}
}
if (base_type(t) == PTR_TO_BTF_ID) if (base_type(t) == PTR_TO_BTF_ID)
verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id)); verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id));
verbose(env, "("); verbose(env, "(");
@ -698,7 +706,7 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st
verbose(env, " R%d", i); verbose(env, " R%d", i);
print_liveness(env, reg->live); print_liveness(env, reg->live);
verbose(env, "="); verbose(env, "=");
print_reg_state(env, reg); print_reg_state(env, state, reg);
} }
for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) {
char types_buf[BPF_REG_SIZE + 1]; char types_buf[BPF_REG_SIZE + 1];
@ -731,7 +739,7 @@ void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_st
verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
print_liveness(env, reg->live); print_liveness(env, reg->live);
verbose(env, "=%s", types_buf); verbose(env, "=%s", types_buf);
print_reg_state(env, reg); print_reg_state(env, state, reg);
break; break;
case STACK_DYNPTR: case STACK_DYNPTR:
/* skip to main dynptr slot */ /* skip to main dynptr slot */