Skip to content

Commit 16b3129

Browse files
author
Alexei Starovoitov
committed
Merge branch 'bpf-verifier-log-improvements'
Andrii Nakryiko says: ==================== BPF verifier log improvements This patch set moves a big chunk of verifier log related code from gigantic verifier.c file into more focused kernel/bpf/log.c. This is not essential to the rest of functionality in this patch set, so I can undo it, but it felt like it's good to start chipping away from 20K+ verifier.c whenever we can. The main purpose of the patch set, though, is in improving verifier log further. Patches #3-#4 start printing out register state even if that register is spilled into stack slot. Previously we'd get only spilled register type, but no additional information, like SCALAR_VALUE's ranges. Super limiting during debugging. For cases of register spills smaller than 8 bytes, we also print out STACK_MISC/STACK_ZERO/STACK_INVALID markers. This, among other things, will make it easier to write tests for these mixed spill/misc cases. Patch #5 prints map name for PTR_TO_MAP_VALUE/PTR_TO_MAP_KEY/CONST_PTR_TO_MAP registers. In big production BPF programs, it's important to map assembly to actual map, and it's often non-trivial. Having map name helps. Patch #6 just removes visual noise in form of ubiquitous imm=0 and off=0. They are default values, omit them. Patch #7 is probably the most controversial, but it reworks how verifier log prints numbers. For small valued integers we use decimals, but for large ones we switch to hexadecimal. From personal experience this is a much more useful convention. We can tune what consitutes "small value", for now it's 16-bit range. Patch #8 prints frame number for PTR_TO_CTX registers, if that frame is different from the "current" one. This removes ambiguity and confusion, especially in complicated cases with multiple subprogs passing around pointers. v2->v3: - adjust reg_bounds tester to parse hex form of reg state as well; - print reg->range as unsigned (Alexei); v1->v2: - use verbose_snum() for range and offset in register state (Eduard); - fixed typos and added acks from Eduard and Stanislav. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents ff8867a + 46862ee commit 16b3129

File tree

8 files changed

+640
-529
lines changed

8 files changed

+640
-529
lines changed

include/linux/bpf_verifier.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,10 @@ int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level,
680680
void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos);
681681
int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual);
682682

683+
__printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env,
684+
u32 insn_off,
685+
const char *prefix_fmt, ...);
686+
683687
static inline struct bpf_func_state *cur_func(struct bpf_verifier_env *env)
684688
{
685689
struct bpf_verifier_state *cur = env->cur_state;
@@ -779,4 +783,76 @@ static inline bool bpf_type_has_unsafe_modifiers(u32 type)
779783
return type_flag(type) & ~BPF_REG_TRUSTED_MODIFIERS;
780784
}
781785

786+
static inline bool type_is_ptr_alloc_obj(u32 type)
787+
{
788+
return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC;
789+
}
790+
791+
static inline bool type_is_non_owning_ref(u32 type)
792+
{
793+
return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF;
794+
}
795+
796+
static inline bool type_is_pkt_pointer(enum bpf_reg_type type)
797+
{
798+
type = base_type(type);
799+
return type == PTR_TO_PACKET ||
800+
type == PTR_TO_PACKET_META;
801+
}
802+
803+
static inline bool type_is_sk_pointer(enum bpf_reg_type type)
804+
{
805+
return type == PTR_TO_SOCKET ||
806+
type == PTR_TO_SOCK_COMMON ||
807+
type == PTR_TO_TCP_SOCK ||
808+
type == PTR_TO_XDP_SOCK;
809+
}
810+
811+
static inline void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno)
812+
{
813+
env->scratched_regs |= 1U << regno;
814+
}
815+
816+
static inline void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi)
817+
{
818+
env->scratched_stack_slots |= 1ULL << spi;
819+
}
820+
821+
static inline bool reg_scratched(const struct bpf_verifier_env *env, u32 regno)
822+
{
823+
return (env->scratched_regs >> regno) & 1;
824+
}
825+
826+
static inline bool stack_slot_scratched(const struct bpf_verifier_env *env, u64 regno)
827+
{
828+
return (env->scratched_stack_slots >> regno) & 1;
829+
}
830+
831+
static inline bool verifier_state_scratched(const struct bpf_verifier_env *env)
832+
{
833+
return env->scratched_regs || env->scratched_stack_slots;
834+
}
835+
836+
static inline void mark_verifier_state_clean(struct bpf_verifier_env *env)
837+
{
838+
env->scratched_regs = 0U;
839+
env->scratched_stack_slots = 0ULL;
840+
}
841+
842+
/* Used for printing the entire verifier state. */
843+
static inline void mark_verifier_state_scratched(struct bpf_verifier_env *env)
844+
{
845+
env->scratched_regs = ~0U;
846+
env->scratched_stack_slots = ~0ULL;
847+
}
848+
849+
const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type);
850+
const char *dynptr_type_str(enum bpf_dynptr_type type);
851+
const char *iter_type_str(const struct btf *btf, u32 btf_id);
852+
const char *iter_state_str(enum bpf_iter_state state);
853+
854+
void print_verifier_state(struct bpf_verifier_env *env,
855+
const struct bpf_func_state *state, bool print_all);
856+
void print_insn_state(struct bpf_verifier_env *env, const struct bpf_func_state *state);
857+
782858
#endif /* _LINUX_BPF_VERIFIER_H */

0 commit comments

Comments
 (0)