xref: /linux/kernel/bpf/diagnostics.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
15ad74616SKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0-only
25ad74616SKumar Kartikeya Dwivedi // Copyright (c) 2026 Meta Platforms, Inc. and affiliates.
35ad74616SKumar Kartikeya Dwivedi 
4b9c5d822SKumar Kartikeya Dwivedi #include <linux/bpf.h>
55ad74616SKumar Kartikeya Dwivedi #include <linux/bpf_verifier.h>
6b9c5d822SKumar Kartikeya Dwivedi #include <linux/btf.h>
75ad74616SKumar Kartikeya Dwivedi #include <linux/ctype.h>
8b9c5d822SKumar Kartikeya Dwivedi #include <linux/kernel.h>
9b9c5d822SKumar Kartikeya Dwivedi #include <linux/list.h>
10b9c5d822SKumar Kartikeya Dwivedi #include <linux/seq_buf.h>
112bdc90f5SKumar Kartikeya Dwivedi #include <linux/overflow.h>
12b9c5d822SKumar Kartikeya Dwivedi #include <linux/slab.h>
135ad74616SKumar Kartikeya Dwivedi #include <linux/stdarg.h>
14b9c5d822SKumar Kartikeya Dwivedi #include <linux/string.h>
155ad74616SKumar Kartikeya Dwivedi 
16b9c5d822SKumar Kartikeya Dwivedi #include "disasm.h"
175ad74616SKumar Kartikeya Dwivedi #include "diagnostics.h"
185ad74616SKumar Kartikeya Dwivedi 
19d63284e6SKumar Kartikeya Dwivedi #define REGISTER_TYPE_SAFETY "Register Type Safety"
202bdc90f5SKumar Kartikeya Dwivedi #define MEMORY_SAFETY "Memory Safety"
215d576462SKumar Kartikeya Dwivedi #define RESOURCE_LIFETIME_SAFETY "Resource Lifetime Safety"
2266e27273SKumar Kartikeya Dwivedi #define CALL_TYPE_SAFETY "Call Type Safety"
2399a6a288SKumar Kartikeya Dwivedi #define EXECUTION_CONTEXT_SAFETY "Execution Context Safety"
24a8f42783SKumar Kartikeya Dwivedi #define PROGRAM_STRUCTURE "Program Structure"
25ac545b00SKumar Kartikeya Dwivedi #define POLICY "Policy"
26d63284e6SKumar Kartikeya Dwivedi 
27b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_WIDTH 100
28d63284e6SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_INDENT "  "
29b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT 2
30b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT_CNT (1 + BPF_DIAG_CONTEXT * 2)
31d63284e6SKumar Kartikeya Dwivedi #define BPF_DIAG_HISTORY_RENDER_MAX 64
32b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_SOURCE_LANE_WIDTH 88
33b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TAB_WIDTH 8
34b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_CHUNK_SIZE (PAGE_SIZE - sizeof(struct diag_fmt_chunk))
35b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_BUF_SIZE 256
36daf82487SKumar Kartikeya Dwivedi #define BPF_DIAG_EVENT_LOG_MAX_SIZE (64U << 20)
37b9c5d822SKumar Kartikeya Dwivedi #define DISASM_LINE_LEN 160
38b9c5d822SKumar Kartikeya Dwivedi 
39af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_target_kind {
40af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_NONE,
41af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_REG,
42af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_ARG,
43af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_SLOT,
44af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_RANGE,
45af4ea6e2SKumar Kartikeya Dwivedi };
46af4ea6e2SKumar Kartikeya Dwivedi 
47af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target {
48af4ea6e2SKumar Kartikeya Dwivedi 	u32 frame_id;
49af4ea6e2SKumar Kartikeya Dwivedi 	union {
50af4ea6e2SKumar Kartikeya Dwivedi 		struct {
51af4ea6e2SKumar Kartikeya Dwivedi 			s16 min_off;
52af4ea6e2SKumar Kartikeya Dwivedi 			s16 max_off;
53af4ea6e2SKumar Kartikeya Dwivedi 		} range;
54af4ea6e2SKumar Kartikeya Dwivedi 		u16 spi;
55af4ea6e2SKumar Kartikeya Dwivedi 		u8 regno;
56af4ea6e2SKumar Kartikeya Dwivedi 		u8 stack_arg;
57af4ea6e2SKumar Kartikeya Dwivedi 	};
58af4ea6e2SKumar Kartikeya Dwivedi 	u8 frameno;
59af4ea6e2SKumar Kartikeya Dwivedi 	u8 kind;
60af4ea6e2SKumar Kartikeya Dwivedi };
61af4ea6e2SKumar Kartikeya Dwivedi 
diag_reg_target(u32 frame_id,u8 frameno,u8 regno)62af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_reg_target(u32 frame_id, u8 frameno, u8 regno)
63af4ea6e2SKumar Kartikeya Dwivedi {
64af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
65af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
66af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
67af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_REG,
68af4ea6e2SKumar Kartikeya Dwivedi 		.regno = regno,
69af4ea6e2SKumar Kartikeya Dwivedi 	};
70af4ea6e2SKumar Kartikeya Dwivedi }
71af4ea6e2SKumar Kartikeya Dwivedi 
diag_stack_arg_target(u32 frame_id,u8 frameno,u8 slot)72af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_arg_target(u32 frame_id, u8 frameno, u8 slot)
73af4ea6e2SKumar Kartikeya Dwivedi {
74af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
75af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
76af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
77af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_STACK_ARG,
78af4ea6e2SKumar Kartikeya Dwivedi 		.stack_arg = slot,
79af4ea6e2SKumar Kartikeya Dwivedi 	};
80af4ea6e2SKumar Kartikeya Dwivedi }
81af4ea6e2SKumar Kartikeya Dwivedi 
diag_stack_slot_target(u32 frame_id,u8 frameno,u16 spi)82af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_slot_target(u32 frame_id, u8 frameno, u16 spi)
83af4ea6e2SKumar Kartikeya Dwivedi {
84af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
85af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
86af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
87af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_STACK_SLOT,
88af4ea6e2SKumar Kartikeya Dwivedi 		.spi = spi,
89af4ea6e2SKumar Kartikeya Dwivedi 	};
90af4ea6e2SKumar Kartikeya Dwivedi }
91af4ea6e2SKumar Kartikeya Dwivedi 
diag_stack_range_target(u32 frame_id,u8 frameno,s16 min_off,s16 max_off)92af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_range_target(u32 frame_id, u8 frameno,
93af4ea6e2SKumar Kartikeya Dwivedi 							  s16 min_off, s16 max_off)
94af4ea6e2SKumar Kartikeya Dwivedi {
95af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
96af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
97af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
98af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_STACK_RANGE,
99af4ea6e2SKumar Kartikeya Dwivedi 		.range.min_off = min_off,
100af4ea6e2SKumar Kartikeya Dwivedi 		.range.max_off = max_off,
101af4ea6e2SKumar Kartikeya Dwivedi 	};
102af4ea6e2SKumar Kartikeya Dwivedi }
103af4ea6e2SKumar Kartikeya Dwivedi 
104af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot {
105af4ea6e2SKumar Kartikeya Dwivedi 	u32 type;
106af4ea6e2SKumar Kartikeya Dwivedi 	u32 btf_id;
107af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_map *map_ptr;
108af4ea6e2SKumar Kartikeya Dwivedi 	const struct btf *btf;
109af4ea6e2SKumar Kartikeya Dwivedi 	struct tnum var_off;
110af4ea6e2SKumar Kartikeya Dwivedi 	struct cnum64 r64;
111af4ea6e2SKumar Kartikeya Dwivedi };
112af4ea6e2SKumar Kartikeya Dwivedi 
113daf82487SKumar Kartikeya Dwivedi enum bpf_diag_history_kind {
114daf82487SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_BRANCH,
115af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_MOD,
1169ecd7030SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_REF_ACQUIRE,
1179ecd7030SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_REF_RELEASE,
118956a66e5SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_CONTEXT,
119daf82487SKumar Kartikeya Dwivedi };
120daf82487SKumar Kartikeya Dwivedi 
121daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event {
122daf82487SKumar Kartikeya Dwivedi 	u32 insn_idx : 24;
123daf82487SKumar Kartikeya Dwivedi 	u32 kind : 8;
124daf82487SKumar Kartikeya Dwivedi 	u8 in_lineage : 1;
125daf82487SKumar Kartikeya Dwivedi 	union {
126daf82487SKumar Kartikeya Dwivedi 		struct {
127daf82487SKumar Kartikeya Dwivedi 			bool cond_true;
128daf82487SKumar Kartikeya Dwivedi 		} branch;
129af4ea6e2SKumar Kartikeya Dwivedi 		struct {
130af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_mod_target target;
131af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_mod_target origin;
132af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_reg_snapshot old, new;
133af4ea6e2SKumar Kartikeya Dwivedi 			u8 reason;
134af4ea6e2SKumar Kartikeya Dwivedi 			bool origin_valid;
135af4ea6e2SKumar Kartikeya Dwivedi 		} mod;
1369ecd7030SKumar Kartikeya Dwivedi 		struct {
1379ecd7030SKumar Kartikeya Dwivedi 			u32 ref_id;
1389ecd7030SKumar Kartikeya Dwivedi 		} ref;
139956a66e5SKumar Kartikeya Dwivedi 		struct {
140956a66e5SKumar Kartikeya Dwivedi 			u32 depth;
141956a66e5SKumar Kartikeya Dwivedi 			u8 kind;
142956a66e5SKumar Kartikeya Dwivedi 			bool enter;
143956a66e5SKumar Kartikeya Dwivedi 		} ctx;
144daf82487SKumar Kartikeya Dwivedi 	};
145daf82487SKumar Kartikeya Dwivedi };
146daf82487SKumar Kartikeya Dwivedi 
147d63284e6SKumar Kartikeya Dwivedi enum bpf_diag_history_scope {
148d63284e6SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_SCOPE_REG,
149d63284e6SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_SCOPE_STACK_ARG,
150d63284e6SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_SCOPE_REF,
151d63284e6SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_SCOPE_CONTEXT,
152d63284e6SKumar Kartikeya Dwivedi };
153d63284e6SKumar Kartikeya Dwivedi 
154d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts {
155d63284e6SKumar Kartikeya Dwivedi 	enum bpf_diag_history_scope scope;
156d63284e6SKumar Kartikeya Dwivedi 	u32 frame_id;
157d63284e6SKumar Kartikeya Dwivedi 	u32 frameno;
158d63284e6SKumar Kartikeya Dwivedi 	int regno;
159d63284e6SKumar Kartikeya Dwivedi 	int stack_arg_slot;
160d63284e6SKumar Kartikeya Dwivedi 	u32 ref_id;
161d63284e6SKumar Kartikeya Dwivedi 	enum bpf_diag_context_kind ctx_kind;
162d63284e6SKumar Kartikeya Dwivedi 	u32 ctx_depth;
163d63284e6SKumar Kartikeya Dwivedi };
164d63284e6SKumar Kartikeya Dwivedi 
165d63284e6SKumar Kartikeya Dwivedi static void diag_print_history(struct bpf_verifier_env *env,
166d63284e6SKumar Kartikeya Dwivedi 			       const struct bpf_diag_history_opts *opts);
167d63284e6SKumar Kartikeya Dwivedi static bool diag_target_matches(const struct bpf_diag_mod_target *event_target,
168d63284e6SKumar Kartikeya Dwivedi 				const struct bpf_diag_mod_target *target);
16999a6a288SKumar Kartikeya Dwivedi static const char *diag_context_name(enum bpf_diag_context_kind kind);
170b9c5d822SKumar Kartikeya Dwivedi struct disasm_line {
171b9c5d822SKumar Kartikeya Dwivedi 	char text[DISASM_LINE_LEN];
172b9c5d822SKumar Kartikeya Dwivedi 	int idx;
173b9c5d822SKumar Kartikeya Dwivedi 	bool valid;
174b9c5d822SKumar Kartikeya Dwivedi };
175b9c5d822SKumar Kartikeya Dwivedi 
176b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx {
177b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_verifier_env *env;
178b9c5d822SKumar Kartikeya Dwivedi 	struct seq_buf seq;
179b9c5d822SKumar Kartikeya Dwivedi };
180b9c5d822SKumar Kartikeya Dwivedi 
181b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk {
182b9c5d822SKumar Kartikeya Dwivedi 	struct list_head node;
183b9c5d822SKumar Kartikeya Dwivedi 	struct seq_buf seq;
184b9c5d822SKumar Kartikeya Dwivedi 	char data[];
185b9c5d822SKumar Kartikeya Dwivedi };
186b9c5d822SKumar Kartikeya Dwivedi 
187b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark {
188b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
189b9c5d822SKumar Kartikeya Dwivedi 	size_t len;
190b9c5d822SKumar Kartikeya Dwivedi };
191b9c5d822SKumar Kartikeya Dwivedi 
192daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log {
193daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event *events;
194daf82487SKumar Kartikeya Dwivedi 	/* Sequence number of the oldest retained event on the active path. */
195daf82487SKumar Kartikeya Dwivedi 	u64 first_seq;
196daf82487SKumar Kartikeya Dwivedi 	u32 cnt;
197daf82487SKumar Kartikeya Dwivedi 	u32 cap;
198daf82487SKumar Kartikeya Dwivedi 	u32 head;
199daf82487SKumar Kartikeya Dwivedi 	bool growth_failed;
200daf82487SKumar Kartikeya Dwivedi };
201daf82487SKumar Kartikeya Dwivedi 
202b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch {
203b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source source_lines[BPF_DIAG_CONTEXT_CNT];
204b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_line disasm_lines[BPF_DIAG_CONTEXT_CNT];
205b9c5d822SKumar Kartikeya Dwivedi };
206b9c5d822SKumar Kartikeya Dwivedi 
207af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope {
208af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_reg_state target_reg_snapshot;
209af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
210af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target origin;
211af4ea6e2SKumar Kartikeya Dwivedi 	enum bpf_diag_mod_reason reason;
212af4ea6e2SKumar Kartikeya Dwivedi 	u32 insn_idx;
213af4ea6e2SKumar Kartikeya Dwivedi 	bool active;
214af4ea6e2SKumar Kartikeya Dwivedi 	bool origin_valid;
215af4ea6e2SKumar Kartikeya Dwivedi };
216af4ea6e2SKumar Kartikeya Dwivedi 
217b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag {
218daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log log;
219b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag_scratch scratch;
220b9c5d822SKumar Kartikeya Dwivedi 	struct list_head fmt_chunks;
221af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_scope mod;
222af4ea6e2SKumar Kartikeya Dwivedi 	u32 frame_id_gen;
223b9c5d822SKumar Kartikeya Dwivedi };
224b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_enabled(const struct bpf_verifier_env * env)2255ad74616SKumar Kartikeya Dwivedi bool bpf_diag_enabled(const struct bpf_verifier_env *env)
2265ad74616SKumar Kartikeya Dwivedi {
2275ad74616SKumar Kartikeya Dwivedi 	return env->log.level & BPF_LOG_LEVEL;
2285ad74616SKumar Kartikeya Dwivedi }
2295ad74616SKumar Kartikeya Dwivedi 
2305ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);
2315ad74616SKumar Kartikeya Dwivedi 
bpf_diag_init(struct bpf_verifier_env * env)232b9c5d822SKumar Kartikeya Dwivedi int bpf_diag_init(struct bpf_verifier_env *env)
233b9c5d822SKumar Kartikeya Dwivedi {
234b9c5d822SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
235b9c5d822SKumar Kartikeya Dwivedi 		return 0;
236b9c5d822SKumar Kartikeya Dwivedi 
237b9c5d822SKumar Kartikeya Dwivedi 	env->diag = kzalloc_obj(struct bpf_diag, GFP_KERNEL_ACCOUNT);
238b9c5d822SKumar Kartikeya Dwivedi 	if (!env->diag)
239b9c5d822SKumar Kartikeya Dwivedi 		return -ENOMEM;
240b9c5d822SKumar Kartikeya Dwivedi 
241b9c5d822SKumar Kartikeya Dwivedi 	INIT_LIST_HEAD(&env->diag->fmt_chunks);
242b9c5d822SKumar Kartikeya Dwivedi 	return 0;
243b9c5d822SKumar Kartikeya Dwivedi }
244b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_init_frame(struct bpf_verifier_env * env,struct bpf_func_state * state)245af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_init_frame(struct bpf_verifier_env *env, struct bpf_func_state *state)
246af4ea6e2SKumar Kartikeya Dwivedi {
247af4ea6e2SKumar Kartikeya Dwivedi 	if (env->diag)
248af4ea6e2SKumar Kartikeya Dwivedi 		state->diag_frame_id = ++env->diag->frame_id_gen;
249af4ea6e2SKumar Kartikeya Dwivedi }
250af4ea6e2SKumar Kartikeya Dwivedi 
diag_fmt_alloc(struct bpf_verifier_env * env,size_t size)251b9c5d822SKumar Kartikeya Dwivedi static char *diag_fmt_alloc(struct bpf_verifier_env *env, size_t size)
252b9c5d822SKumar Kartikeya Dwivedi {
253b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
254b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
255b9c5d822SKumar Kartikeya Dwivedi 	size_t capacity, available;
256b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
257b9c5d822SKumar Kartikeya Dwivedi 
258b9c5d822SKumar Kartikeya Dwivedi 	if (!diag || !size || size > INT_MAX)
259b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
260b9c5d822SKumar Kartikeya Dwivedi 
261b9c5d822SKumar Kartikeya Dwivedi 	if (!list_empty(&diag->fmt_chunks)) {
262b9c5d822SKumar Kartikeya Dwivedi 		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
263b9c5d822SKumar Kartikeya Dwivedi 		available = seq_buf_get_buf(&chunk->seq, &buf);
264b9c5d822SKumar Kartikeya Dwivedi 		if (available >= size)
265b9c5d822SKumar Kartikeya Dwivedi 			goto commit;
266b9c5d822SKumar Kartikeya Dwivedi 	}
267b9c5d822SKumar Kartikeya Dwivedi 
268b9c5d822SKumar Kartikeya Dwivedi 	capacity = max_t(size_t, BPF_DIAG_FMT_CHUNK_SIZE, size);
269b9c5d822SKumar Kartikeya Dwivedi 	chunk = kmalloc(struct_size(chunk, data, capacity), GFP_KERNEL_ACCOUNT);
270b9c5d822SKumar Kartikeya Dwivedi 	if (!chunk)
271b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
272b9c5d822SKumar Kartikeya Dwivedi 
273b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_init(&chunk->seq, chunk->data, capacity);
274b9c5d822SKumar Kartikeya Dwivedi 	list_add_tail(&chunk->node, &diag->fmt_chunks);
275b9c5d822SKumar Kartikeya Dwivedi 	available = seq_buf_get_buf(&chunk->seq, &buf);
276b9c5d822SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(available < size))
277b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
278b9c5d822SKumar Kartikeya Dwivedi 
279b9c5d822SKumar Kartikeya Dwivedi commit:
280b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_commit(&chunk->seq, size);
281b9c5d822SKumar Kartikeya Dwivedi 	return buf;
282b9c5d822SKumar Kartikeya Dwivedi }
283b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_fmt_buf(struct bpf_verifier_env * env,size_t size)284b9c5d822SKumar Kartikeya Dwivedi char *bpf_diag_fmt_buf(struct bpf_verifier_env *env, size_t size)
285b9c5d822SKumar Kartikeya Dwivedi {
286b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
287b9c5d822SKumar Kartikeya Dwivedi 
288b9c5d822SKumar Kartikeya Dwivedi 	buf = diag_fmt_alloc(env, size);
289b9c5d822SKumar Kartikeya Dwivedi 	if (buf)
290b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
291b9c5d822SKumar Kartikeya Dwivedi 	return buf;
292b9c5d822SKumar Kartikeya Dwivedi }
293b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_vfmt(struct bpf_verifier_env * env,const char * fmt,va_list args)294b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list args)
295b9c5d822SKumar Kartikeya Dwivedi {
296b9c5d822SKumar Kartikeya Dwivedi 	va_list copy;
297b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
298b9c5d822SKumar Kartikeya Dwivedi 	int len;
299b9c5d822SKumar Kartikeya Dwivedi 
300b9c5d822SKumar Kartikeya Dwivedi 	va_copy(copy, args);
301b9c5d822SKumar Kartikeya Dwivedi 	len = vsnprintf(NULL, 0, fmt, copy);
302b9c5d822SKumar Kartikeya Dwivedi 	va_end(copy);
303b9c5d822SKumar Kartikeya Dwivedi 	if (len < 0 || len == INT_MAX)
304b9c5d822SKumar Kartikeya Dwivedi 		return "";
305b9c5d822SKumar Kartikeya Dwivedi 
306b9c5d822SKumar Kartikeya Dwivedi 	buf = diag_fmt_alloc(env, len + 1);
307b9c5d822SKumar Kartikeya Dwivedi 	if (buf)
308b9c5d822SKumar Kartikeya Dwivedi 		vsnprintf(buf, len + 1, fmt, args);
309b9c5d822SKumar Kartikeya Dwivedi 	return buf ?: "";
310b9c5d822SKumar Kartikeya Dwivedi }
311b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_fmt(struct bpf_verifier_env * env,const char * fmt,...)312b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...)
313b9c5d822SKumar Kartikeya Dwivedi {
314b9c5d822SKumar Kartikeya Dwivedi 	const char *buf;
315b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
316b9c5d822SKumar Kartikeya Dwivedi 
317b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
318b9c5d822SKumar Kartikeya Dwivedi 	buf = bpf_diag_vfmt(env, fmt, args);
319b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
320b9c5d822SKumar Kartikeya Dwivedi 	return buf;
321b9c5d822SKumar Kartikeya Dwivedi }
322b9c5d822SKumar Kartikeya Dwivedi 
diag_fmt_save(struct bpf_verifier_env * env)323b9c5d822SKumar Kartikeya Dwivedi static struct diag_fmt_mark diag_fmt_save(struct bpf_verifier_env *env)
324b9c5d822SKumar Kartikeya Dwivedi {
325b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
326b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_mark mark = {};
327b9c5d822SKumar Kartikeya Dwivedi 
328b9c5d822SKumar Kartikeya Dwivedi 	if (!diag || list_empty(&diag->fmt_chunks))
329b9c5d822SKumar Kartikeya Dwivedi 		return mark;
330b9c5d822SKumar Kartikeya Dwivedi 
331b9c5d822SKumar Kartikeya Dwivedi 	mark.chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
332b9c5d822SKumar Kartikeya Dwivedi 	mark.len = mark.chunk->seq.len;
333b9c5d822SKumar Kartikeya Dwivedi 	return mark;
334b9c5d822SKumar Kartikeya Dwivedi }
335b9c5d822SKumar Kartikeya Dwivedi 
diag_fmt_restore(struct bpf_verifier_env * env,struct diag_fmt_mark mark)336b9c5d822SKumar Kartikeya Dwivedi static void diag_fmt_restore(struct bpf_verifier_env *env, struct diag_fmt_mark mark)
337b9c5d822SKumar Kartikeya Dwivedi {
338b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
339b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
340b9c5d822SKumar Kartikeya Dwivedi 
341b9c5d822SKumar Kartikeya Dwivedi 	if (!diag)
342b9c5d822SKumar Kartikeya Dwivedi 		return;
343b9c5d822SKumar Kartikeya Dwivedi 
344b9c5d822SKumar Kartikeya Dwivedi 	while (!list_empty(&diag->fmt_chunks)) {
345b9c5d822SKumar Kartikeya Dwivedi 		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
346b9c5d822SKumar Kartikeya Dwivedi 		if (chunk == mark.chunk)
347b9c5d822SKumar Kartikeya Dwivedi 			break;
348b9c5d822SKumar Kartikeya Dwivedi 		list_del(&chunk->node);
349b9c5d822SKumar Kartikeya Dwivedi 		kfree(chunk);
350b9c5d822SKumar Kartikeya Dwivedi 	}
351b9c5d822SKumar Kartikeya Dwivedi 
352b9c5d822SKumar Kartikeya Dwivedi 	if (mark.chunk) {
353b9c5d822SKumar Kartikeya Dwivedi 		mark.chunk->seq.len = mark.len;
354b9c5d822SKumar Kartikeya Dwivedi 		seq_buf_str(&mark.chunk->seq);
355b9c5d822SKumar Kartikeya Dwivedi 	}
356b9c5d822SKumar Kartikeya Dwivedi }
357b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_free(struct bpf_verifier_env * env)358b9c5d822SKumar Kartikeya Dwivedi void bpf_diag_free(struct bpf_verifier_env *env)
359b9c5d822SKumar Kartikeya Dwivedi {
360b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
361b9c5d822SKumar Kartikeya Dwivedi 
362b9c5d822SKumar Kartikeya Dwivedi 	if (!diag)
363b9c5d822SKumar Kartikeya Dwivedi 		return;
364b9c5d822SKumar Kartikeya Dwivedi 
365b9c5d822SKumar Kartikeya Dwivedi 	diag_fmt_restore(env, (struct diag_fmt_mark){});
366daf82487SKumar Kartikeya Dwivedi 	kvfree(diag->log.events);
367b9c5d822SKumar Kartikeya Dwivedi 	kfree(diag);
368b9c5d822SKumar Kartikeya Dwivedi 	env->diag = NULL;
369b9c5d822SKumar Kartikeya Dwivedi }
370b9c5d822SKumar Kartikeya Dwivedi 
diag_write(struct bpf_verifier_env * env,const char * fmt,...)3715ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...)
3725ad74616SKumar Kartikeya Dwivedi {
3735ad74616SKumar Kartikeya Dwivedi 	va_list args;
3745ad74616SKumar Kartikeya Dwivedi 
3755ad74616SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
3765ad74616SKumar Kartikeya Dwivedi 		return;
3775ad74616SKumar Kartikeya Dwivedi 
3785ad74616SKumar Kartikeya Dwivedi 	va_start(args, fmt);
3795ad74616SKumar Kartikeya Dwivedi 	bpf_verifier_vlog(&env->log, fmt, args);
3805ad74616SKumar Kartikeya Dwivedi 	va_end(args);
3815ad74616SKumar Kartikeya Dwivedi }
3825ad74616SKumar Kartikeya Dwivedi 
log_end(const struct bpf_diag_log * log)383daf82487SKumar Kartikeya Dwivedi static u64 log_end(const struct bpf_diag_log *log)
384daf82487SKumar Kartikeya Dwivedi {
385daf82487SKumar Kartikeya Dwivedi 	return log->first_seq + log->cnt;
386daf82487SKumar Kartikeya Dwivedi }
387daf82487SKumar Kartikeya Dwivedi 
log_pos(const struct bpf_diag_log * log,u32 idx)388daf82487SKumar Kartikeya Dwivedi static u32 log_pos(const struct bpf_diag_log *log, u32 idx)
389daf82487SKumar Kartikeya Dwivedi {
390daf82487SKumar Kartikeya Dwivedi 	u32 pos = log->head + idx;
391daf82487SKumar Kartikeya Dwivedi 
392daf82487SKumar Kartikeya Dwivedi 	return pos < log->cap ? pos : pos - log->cap;
393daf82487SKumar Kartikeya Dwivedi }
394daf82487SKumar Kartikeya Dwivedi 
bpf_diag_event_log_save(struct bpf_verifier_env * env)395daf82487SKumar Kartikeya Dwivedi u64 bpf_diag_event_log_save(struct bpf_verifier_env *env)
396daf82487SKumar Kartikeya Dwivedi {
397daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
398daf82487SKumar Kartikeya Dwivedi 
399daf82487SKumar Kartikeya Dwivedi 	return diag ? log_end(&diag->log) : 0;
400daf82487SKumar Kartikeya Dwivedi }
401daf82487SKumar Kartikeya Dwivedi 
bpf_diag_event_log_restore(struct bpf_verifier_env * env,u64 log_pos)402daf82487SKumar Kartikeya Dwivedi void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos)
403daf82487SKumar Kartikeya Dwivedi {
404daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
405daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log *log;
406daf82487SKumar Kartikeya Dwivedi 	u64 end_seq;
407daf82487SKumar Kartikeya Dwivedi 
408daf82487SKumar Kartikeya Dwivedi 	if (!diag)
409daf82487SKumar Kartikeya Dwivedi 		return;
410daf82487SKumar Kartikeya Dwivedi 
411daf82487SKumar Kartikeya Dwivedi 	log = &diag->log;
412daf82487SKumar Kartikeya Dwivedi 	end_seq = log_end(log);
413daf82487SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(log_pos > end_seq))
414daf82487SKumar Kartikeya Dwivedi 		log_pos = end_seq;
415daf82487SKumar Kartikeya Dwivedi 
416daf82487SKumar Kartikeya Dwivedi 	/*
417daf82487SKumar Kartikeya Dwivedi 	 * A deep abandoned path may have rotated away the shared prefix. In
418daf82487SKumar Kartikeya Dwivedi 	 * that case, restart with an empty retained suffix and remember that
419daf82487SKumar Kartikeya Dwivedi 	 * every event before the restored mark is unavailable.
420daf82487SKumar Kartikeya Dwivedi 	 */
421daf82487SKumar Kartikeya Dwivedi 	if (log_pos <= log->first_seq) {
422daf82487SKumar Kartikeya Dwivedi 		log->first_seq = log_pos;
423daf82487SKumar Kartikeya Dwivedi 		log->head = 0;
424daf82487SKumar Kartikeya Dwivedi 		log->cnt = 0;
425daf82487SKumar Kartikeya Dwivedi 		return;
426daf82487SKumar Kartikeya Dwivedi 	}
427daf82487SKumar Kartikeya Dwivedi 
428daf82487SKumar Kartikeya Dwivedi 	log->cnt = log_pos - log->first_seq;
429daf82487SKumar Kartikeya Dwivedi }
430daf82487SKumar Kartikeya Dwivedi 
bpf_diag_irq_depth(const struct bpf_verifier_state * state)431956a66e5SKumar Kartikeya Dwivedi u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state)
432956a66e5SKumar Kartikeya Dwivedi {
433956a66e5SKumar Kartikeya Dwivedi 	u32 depth = 0;
434956a66e5SKumar Kartikeya Dwivedi 	int i;
435956a66e5SKumar Kartikeya Dwivedi 
436956a66e5SKumar Kartikeya Dwivedi 	for (i = 0; i < state->acquired_refs; i++) {
437956a66e5SKumar Kartikeya Dwivedi 		if (state->refs[i].type == REF_TYPE_IRQ)
438956a66e5SKumar Kartikeya Dwivedi 			depth++;
439956a66e5SKumar Kartikeya Dwivedi 	}
440956a66e5SKumar Kartikeya Dwivedi 
441956a66e5SKumar Kartikeya Dwivedi 	return depth;
442956a66e5SKumar Kartikeya Dwivedi }
443956a66e5SKumar Kartikeya Dwivedi 
diag_append_history(struct bpf_verifier_env * env,const struct bpf_diag_history_event * event)444daf82487SKumar Kartikeya Dwivedi static void diag_append_history(struct bpf_verifier_env *env,
445daf82487SKumar Kartikeya Dwivedi 				const struct bpf_diag_history_event *event)
446daf82487SKumar Kartikeya Dwivedi {
447daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event *events;
448daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
449daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log *log;
450daf82487SKumar Kartikeya Dwivedi 	u32 cap, max_events;
451daf82487SKumar Kartikeya Dwivedi 
452daf82487SKumar Kartikeya Dwivedi 	if (!diag)
453daf82487SKumar Kartikeya Dwivedi 		return;
454daf82487SKumar Kartikeya Dwivedi 	log = &diag->log;
455daf82487SKumar Kartikeya Dwivedi 
456daf82487SKumar Kartikeya Dwivedi 	if (log->cnt < log->cap) {
457daf82487SKumar Kartikeya Dwivedi 		log->events[log_pos(log, log->cnt++)] = *event;
458daf82487SKumar Kartikeya Dwivedi 		return;
459daf82487SKumar Kartikeya Dwivedi 	}
460daf82487SKumar Kartikeya Dwivedi 
461daf82487SKumar Kartikeya Dwivedi 	max_events = BPF_DIAG_EVENT_LOG_MAX_SIZE / sizeof(*events);
462daf82487SKumar Kartikeya Dwivedi 	if (log->growth_failed || log->cap == max_events)
463daf82487SKumar Kartikeya Dwivedi 		goto rotate;
464daf82487SKumar Kartikeya Dwivedi 
465daf82487SKumar Kartikeya Dwivedi 	cap = min(log->cap ? log->cap * 2 : 64, max_events);
466daf82487SKumar Kartikeya Dwivedi 	events = kvrealloc(log->events, array_size(cap, sizeof(*events)), GFP_KERNEL_ACCOUNT);
467daf82487SKumar Kartikeya Dwivedi 	if (!events) {
468daf82487SKumar Kartikeya Dwivedi 		log->growth_failed = true;
469daf82487SKumar Kartikeya Dwivedi 		goto rotate;
470daf82487SKumar Kartikeya Dwivedi 	}
471daf82487SKumar Kartikeya Dwivedi 	log->events = events;
472daf82487SKumar Kartikeya Dwivedi 	log->cap = cap;
473daf82487SKumar Kartikeya Dwivedi 	log->events[log->cnt++] = *event;
474daf82487SKumar Kartikeya Dwivedi 	return;
475daf82487SKumar Kartikeya Dwivedi 
476daf82487SKumar Kartikeya Dwivedi rotate:
477daf82487SKumar Kartikeya Dwivedi 	if (log->cap) {
478daf82487SKumar Kartikeya Dwivedi 		log->events[log->head++] = *event;
479daf82487SKumar Kartikeya Dwivedi 		if (log->head == log->cap)
480daf82487SKumar Kartikeya Dwivedi 			log->head = 0;
481daf82487SKumar Kartikeya Dwivedi 	}
482daf82487SKumar Kartikeya Dwivedi 	log->first_seq++;
483daf82487SKumar Kartikeya Dwivedi }
484daf82487SKumar Kartikeya Dwivedi 
diag_print_wrapped_prefixed(struct bpf_verifier_env * env,const char * first_prefix,const char * next_prefix,const char * text)485b9c5d822SKumar Kartikeya Dwivedi static void diag_print_wrapped_prefixed(struct bpf_verifier_env *env, const char *first_prefix,
486b9c5d822SKumar Kartikeya Dwivedi 					const char *next_prefix, const char *text)
487b9c5d822SKumar Kartikeya Dwivedi {
488b9c5d822SKumar Kartikeya Dwivedi 	const char *prefix = first_prefix;
489b9c5d822SKumar Kartikeya Dwivedi 
490b9c5d822SKumar Kartikeya Dwivedi 	while (*text) {
491b9c5d822SKumar Kartikeya Dwivedi 		const char *line = text;
492b9c5d822SKumar Kartikeya Dwivedi 		int prefix_len = strlen(prefix);
493b9c5d822SKumar Kartikeya Dwivedi 		int text_width = BPF_DIAG_TEXT_WIDTH - prefix_len;
494b9c5d822SKumar Kartikeya Dwivedi 		int len = 0, last_space = -1;
495b9c5d822SKumar Kartikeya Dwivedi 
496b9c5d822SKumar Kartikeya Dwivedi 		if (text_width < 1)
497b9c5d822SKumar Kartikeya Dwivedi 			text_width = 1;
498b9c5d822SKumar Kartikeya Dwivedi 
499b9c5d822SKumar Kartikeya Dwivedi 		while (line[len] && line[len] != '\n' && len < text_width) {
500b9c5d822SKumar Kartikeya Dwivedi 			if (line[len] == ' ')
501b9c5d822SKumar Kartikeya Dwivedi 				last_space = len;
502b9c5d822SKumar Kartikeya Dwivedi 			len++;
503b9c5d822SKumar Kartikeya Dwivedi 		}
504b9c5d822SKumar Kartikeya Dwivedi 
505b9c5d822SKumar Kartikeya Dwivedi 		if (line[len] && line[len] != '\n' && line[len] != ' ' && last_space > 0)
506b9c5d822SKumar Kartikeya Dwivedi 			len = last_space;
507b9c5d822SKumar Kartikeya Dwivedi 
508b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "%s%.*s\n", prefix, len, line);
509b9c5d822SKumar Kartikeya Dwivedi 
510b9c5d822SKumar Kartikeya Dwivedi 		text = line + len;
511b9c5d822SKumar Kartikeya Dwivedi 		while (*text == ' ')
512b9c5d822SKumar Kartikeya Dwivedi 			text++;
513b9c5d822SKumar Kartikeya Dwivedi 		if (*text == '\n')
514b9c5d822SKumar Kartikeya Dwivedi 			text++;
515b9c5d822SKumar Kartikeya Dwivedi 
516b9c5d822SKumar Kartikeya Dwivedi 		prefix = next_prefix;
517b9c5d822SKumar Kartikeya Dwivedi 	}
518b9c5d822SKumar Kartikeya Dwivedi }
519b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_fmt_btf_type(struct bpf_verifier_env * env,const struct btf * btf,u32 type_id)520af4ea6e2SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id)
521af4ea6e2SKumar Kartikeya Dwivedi {
522af4ea6e2SKumar Kartikeya Dwivedi 	char *buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE);
523af4ea6e2SKumar Kartikeya Dwivedi 	size_t len;
524af4ea6e2SKumar Kartikeya Dwivedi 	int ret;
525af4ea6e2SKumar Kartikeya Dwivedi 
526af4ea6e2SKumar Kartikeya Dwivedi 	if (!buf)
527af4ea6e2SKumar Kartikeya Dwivedi 		return "";
528af4ea6e2SKumar Kartikeya Dwivedi 
529af4ea6e2SKumar Kartikeya Dwivedi 	buf[0] = '\0';
530af4ea6e2SKumar Kartikeya Dwivedi 	ret = btf_type_name_to_buf(btf, type_id, buf, BPF_DIAG_FMT_BUF_SIZE);
531af4ea6e2SKumar Kartikeya Dwivedi 	if (ret < 0 || !buf[0]) {
532af4ea6e2SKumar Kartikeya Dwivedi 		scnprintf(buf, BPF_DIAG_FMT_BUF_SIZE, "BTF type ID %u", type_id);
533af4ea6e2SKumar Kartikeya Dwivedi 		return buf;
534af4ea6e2SKumar Kartikeya Dwivedi 	}
535af4ea6e2SKumar Kartikeya Dwivedi 
536af4ea6e2SKumar Kartikeya Dwivedi 	len = strlen(buf);
537af4ea6e2SKumar Kartikeya Dwivedi 	if (len && buf[len - 1] == '{')
538af4ea6e2SKumar Kartikeya Dwivedi 		buf[len - 1] = '\0';
539af4ea6e2SKumar Kartikeya Dwivedi 	return buf;
540af4ea6e2SKumar Kartikeya Dwivedi }
541af4ea6e2SKumar Kartikeya Dwivedi 
542d63284e6SKumar Kartikeya Dwivedi static void diag_vprint_indented(struct bpf_verifier_env *env, const char *fmt, va_list args)
543d63284e6SKumar Kartikeya Dwivedi 	__printf(2, 0);
544d63284e6SKumar Kartikeya Dwivedi 
diag_vprint_indented(struct bpf_verifier_env * env,const char * fmt,va_list args)545d63284e6SKumar Kartikeya Dwivedi static void diag_vprint_indented(struct bpf_verifier_env *env, const char *fmt, va_list args)
546d63284e6SKumar Kartikeya Dwivedi {
547d63284e6SKumar Kartikeya Dwivedi 	char *buf;
548d63284e6SKumar Kartikeya Dwivedi 
549d63284e6SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
550d63284e6SKumar Kartikeya Dwivedi 		return;
551d63284e6SKumar Kartikeya Dwivedi 
552d63284e6SKumar Kartikeya Dwivedi 	buf = kvasprintf(GFP_KERNEL_ACCOUNT, fmt, args);
553d63284e6SKumar Kartikeya Dwivedi 	if (!buf) {
554d63284e6SKumar Kartikeya Dwivedi 		diag_write(env, "%s<failed to allocate diagnostic text>\n", BPF_DIAG_TEXT_INDENT);
555d63284e6SKumar Kartikeya Dwivedi 		return;
556d63284e6SKumar Kartikeya Dwivedi 	}
557d63284e6SKumar Kartikeya Dwivedi 
558d63284e6SKumar Kartikeya Dwivedi 	diag_print_wrapped_prefixed(env, BPF_DIAG_TEXT_INDENT, BPF_DIAG_TEXT_INDENT, buf);
559d63284e6SKumar Kartikeya Dwivedi 	kfree(buf);
560d63284e6SKumar Kartikeya Dwivedi }
561d63284e6SKumar Kartikeya Dwivedi 
diag_line_width(unsigned int line)562b9c5d822SKumar Kartikeya Dwivedi static int diag_line_width(unsigned int line)
563b9c5d822SKumar Kartikeya Dwivedi {
564b9c5d822SKumar Kartikeya Dwivedi 	int width = 1;
565b9c5d822SKumar Kartikeya Dwivedi 
566b9c5d822SKumar Kartikeya Dwivedi 	while (line >= 10) {
567b9c5d822SKumar Kartikeya Dwivedi 		line /= 10;
568b9c5d822SKumar Kartikeya Dwivedi 		width++;
569b9c5d822SKumar Kartikeya Dwivedi 	}
570b9c5d822SKumar Kartikeya Dwivedi 
571b9c5d822SKumar Kartikeya Dwivedi 	return width;
572b9c5d822SKumar Kartikeya Dwivedi }
573b9c5d822SKumar Kartikeya Dwivedi 
diag_line_indent(const char * line)574b9c5d822SKumar Kartikeya Dwivedi static int diag_line_indent(const char *line)
575b9c5d822SKumar Kartikeya Dwivedi {
576b9c5d822SKumar Kartikeya Dwivedi 	int indent = 0;
577b9c5d822SKumar Kartikeya Dwivedi 
578b9c5d822SKumar Kartikeya Dwivedi 	while (*line == ' ' || *line == '\t') {
579b9c5d822SKumar Kartikeya Dwivedi 		if (*line == '\t')
580b9c5d822SKumar Kartikeya Dwivedi 			indent = round_up(indent + 1, BPF_DIAG_TAB_WIDTH);
581b9c5d822SKumar Kartikeya Dwivedi 		else
582b9c5d822SKumar Kartikeya Dwivedi 			indent++;
583b9c5d822SKumar Kartikeya Dwivedi 		line++;
584b9c5d822SKumar Kartikeya Dwivedi 	}
585b9c5d822SKumar Kartikeya Dwivedi 
586b9c5d822SKumar Kartikeya Dwivedi 	return indent;
587b9c5d822SKumar Kartikeya Dwivedi }
588b9c5d822SKumar Kartikeya Dwivedi 
589b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) __printf(2, 3);
590b9c5d822SKumar Kartikeya Dwivedi 
disasm_print(void * private_data,const char * fmt,...)591b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...)
592b9c5d822SKumar Kartikeya Dwivedi {
593b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx *ctx = private_data;
594b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
595b9c5d822SKumar Kartikeya Dwivedi 
596b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
597b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_vprintf(&ctx->seq, fmt, args);
598b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
599b9c5d822SKumar Kartikeya Dwivedi }
600b9c5d822SKumar Kartikeya Dwivedi 
disasm_kfunc_name(void * private_data,const struct bpf_insn * insn)601b9c5d822SKumar Kartikeya Dwivedi static const char *disasm_kfunc_name(void *private_data, const struct bpf_insn *insn)
602b9c5d822SKumar Kartikeya Dwivedi {
603b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx *ctx = private_data;
604b9c5d822SKumar Kartikeya Dwivedi 
605b9c5d822SKumar Kartikeya Dwivedi 	return bpf_disasm_kfunc_name(ctx->env, insn);
606b9c5d822SKumar Kartikeya Dwivedi }
607b9c5d822SKumar Kartikeya Dwivedi 
format_disasm_line(struct bpf_verifier_env * env,int insn_idx,struct disasm_line * line)608b9c5d822SKumar Kartikeya Dwivedi static void format_disasm_line(struct bpf_verifier_env *env, int insn_idx,
609b9c5d822SKumar Kartikeya Dwivedi 			       struct disasm_line *line)
610b9c5d822SKumar Kartikeya Dwivedi {
611b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx ctx = { .env = env };
612b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_insn *insn;
613b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_insn_cbs cbs = {
614b9c5d822SKumar Kartikeya Dwivedi 		.cb_call = disasm_kfunc_name,
615b9c5d822SKumar Kartikeya Dwivedi 		.cb_print = disasm_print,
616b9c5d822SKumar Kartikeya Dwivedi 		.private_data = &ctx,
617b9c5d822SKumar Kartikeya Dwivedi 	};
618b9c5d822SKumar Kartikeya Dwivedi 
619b9c5d822SKumar Kartikeya Dwivedi 	line->idx = insn_idx;
620b9c5d822SKumar Kartikeya Dwivedi 	line->valid = false;
621b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_init(&ctx.seq, line->text, sizeof(line->text));
622b9c5d822SKumar Kartikeya Dwivedi 
623b9c5d822SKumar Kartikeya Dwivedi 	if (insn_idx < 0 || insn_idx >= env->prog->len)
624b9c5d822SKumar Kartikeya Dwivedi 		return;
625b9c5d822SKumar Kartikeya Dwivedi 
626b9c5d822SKumar Kartikeya Dwivedi 	if (insn_idx > 0 && bpf_is_ldimm64(&env->prog->insnsi[insn_idx - 1]))
627b9c5d822SKumar Kartikeya Dwivedi 		return;
628b9c5d822SKumar Kartikeya Dwivedi 
629b9c5d822SKumar Kartikeya Dwivedi 	insn = &env->prog->insnsi[insn_idx];
630b9c5d822SKumar Kartikeya Dwivedi 	if (bpf_is_ldimm64(insn) && insn_idx + 1 >= env->prog->len)
631b9c5d822SKumar Kartikeya Dwivedi 		return;
632b9c5d822SKumar Kartikeya Dwivedi 
633b9c5d822SKumar Kartikeya Dwivedi 	print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
634b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_str(&ctx.seq);
635b9c5d822SKumar Kartikeya Dwivedi 	ctx.seq.len = strnlen(line->text, sizeof(line->text));
636b9c5d822SKumar Kartikeya Dwivedi 	while (ctx.seq.len && line->text[ctx.seq.len - 1] == '\n')
637b9c5d822SKumar Kartikeya Dwivedi 		seq_buf_pop(&ctx.seq);
638b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_str(&ctx.seq);
639b9c5d822SKumar Kartikeya Dwivedi 
640b9c5d822SKumar Kartikeya Dwivedi 	line->valid = true;
641b9c5d822SKumar Kartikeya Dwivedi }
642b9c5d822SKumar Kartikeya Dwivedi 
diag_format_source_text(char * buf,size_t size,const char * line,int width)643b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_text(char *buf, size_t size, const char *line, int width)
644b9c5d822SKumar Kartikeya Dwivedi {
645b9c5d822SKumar Kartikeya Dwivedi 	int col = 0, len = 0;
646b9c5d822SKumar Kartikeya Dwivedi 
647b9c5d822SKumar Kartikeya Dwivedi 	if (!size)
648b9c5d822SKumar Kartikeya Dwivedi 		return;
649b9c5d822SKumar Kartikeya Dwivedi 	if (width <= 0) {
650b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
651b9c5d822SKumar Kartikeya Dwivedi 		return;
652b9c5d822SKumar Kartikeya Dwivedi 	}
653b9c5d822SKumar Kartikeya Dwivedi 
654b9c5d822SKumar Kartikeya Dwivedi 	line = line ?: "...";
655b9c5d822SKumar Kartikeya Dwivedi 	while (*line && col < width && len + 1 < size) {
656b9c5d822SKumar Kartikeya Dwivedi 		if (*line == '\t') {
657b9c5d822SKumar Kartikeya Dwivedi 			int next = round_up(col + 1, BPF_DIAG_TAB_WIDTH);
658b9c5d822SKumar Kartikeya Dwivedi 
659b9c5d822SKumar Kartikeya Dwivedi 			while (col < next && col < width && len + 1 < size) {
660b9c5d822SKumar Kartikeya Dwivedi 				buf[len++] = ' ';
661b9c5d822SKumar Kartikeya Dwivedi 				col++;
662b9c5d822SKumar Kartikeya Dwivedi 			}
663b9c5d822SKumar Kartikeya Dwivedi 			line++;
664b9c5d822SKumar Kartikeya Dwivedi 			continue;
665b9c5d822SKumar Kartikeya Dwivedi 		}
666b9c5d822SKumar Kartikeya Dwivedi 
667b9c5d822SKumar Kartikeya Dwivedi 		buf[len++] = *line++;
668b9c5d822SKumar Kartikeya Dwivedi 		col++;
669b9c5d822SKumar Kartikeya Dwivedi 	}
670b9c5d822SKumar Kartikeya Dwivedi 
671b9c5d822SKumar Kartikeya Dwivedi 	if (*line) {
672b9c5d822SKumar Kartikeya Dwivedi 		int ellipsis_len = min(3, width);
673b9c5d822SKumar Kartikeya Dwivedi 
674b9c5d822SKumar Kartikeya Dwivedi 		while (len > 0 && col > width - ellipsis_len) {
675b9c5d822SKumar Kartikeya Dwivedi 			len--;
676b9c5d822SKumar Kartikeya Dwivedi 			col--;
677b9c5d822SKumar Kartikeya Dwivedi 		}
678b9c5d822SKumar Kartikeya Dwivedi 		while (ellipsis_len-- && len + 1 < size)
679b9c5d822SKumar Kartikeya Dwivedi 			buf[len++] = '.';
680b9c5d822SKumar Kartikeya Dwivedi 	}
681b9c5d822SKumar Kartikeya Dwivedi 
682b9c5d822SKumar Kartikeya Dwivedi 	buf[len] = '\0';
683b9c5d822SKumar Kartikeya Dwivedi }
684b9c5d822SKumar Kartikeya Dwivedi 
diag_format_source_lane(char * buf,size_t size,const char * source_prefix,int source_line_width,int line_num,const char * line)685b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_lane(char *buf, size_t size, const char *source_prefix,
686b9c5d822SKumar Kartikeya Dwivedi 				    int source_line_width, int line_num, const char *line)
687b9c5d822SKumar Kartikeya Dwivedi {
688b9c5d822SKumar Kartikeya Dwivedi 	int len, text_width;
689b9c5d822SKumar Kartikeya Dwivedi 
690b9c5d822SKumar Kartikeya Dwivedi 	if (line_num <= 0) {
691b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
692b9c5d822SKumar Kartikeya Dwivedi 		return;
693b9c5d822SKumar Kartikeya Dwivedi 	}
694b9c5d822SKumar Kartikeya Dwivedi 
695b9c5d822SKumar Kartikeya Dwivedi 	len = scnprintf(buf, size, "%s%*d | ", source_prefix, source_line_width, line_num);
696b9c5d822SKumar Kartikeya Dwivedi 	text_width = BPF_DIAG_SOURCE_LANE_WIDTH - len;
697b9c5d822SKumar Kartikeya Dwivedi 	diag_format_source_text(buf + len, size - len, line, text_width);
698b9c5d822SKumar Kartikeya Dwivedi }
699b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_header(struct bpf_verifier_env * env,const char * category,const char * problem)7005ad74616SKumar Kartikeya Dwivedi static void bpf_diag_header(struct bpf_verifier_env *env, const char *category,
7015ad74616SKumar Kartikeya Dwivedi 			    const char *problem)
7025ad74616SKumar Kartikeya Dwivedi {
7035ad74616SKumar Kartikeya Dwivedi 	char first;
7045ad74616SKumar Kartikeya Dwivedi 
7055ad74616SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
7065ad74616SKumar Kartikeya Dwivedi 		return;
7075ad74616SKumar Kartikeya Dwivedi 
7085ad74616SKumar Kartikeya Dwivedi 	category = category ?: "Verifier Error";
7095ad74616SKumar Kartikeya Dwivedi 	problem = problem ?: "";
7105ad74616SKumar Kartikeya Dwivedi 
7115ad74616SKumar Kartikeya Dwivedi 	if (!problem[0]) {
7125ad74616SKumar Kartikeya Dwivedi 		diag_write(env, "\nVerification failed: %s\n", category);
7135ad74616SKumar Kartikeya Dwivedi 		return;
7145ad74616SKumar Kartikeya Dwivedi 	}
7155ad74616SKumar Kartikeya Dwivedi 
7165ad74616SKumar Kartikeya Dwivedi 	first = toupper(problem[0]);
7175ad74616SKumar Kartikeya Dwivedi 	diag_write(env, "\nVerification failed: %s: %c%s\n", category, first, problem + 1);
7185ad74616SKumar Kartikeya Dwivedi }
719b9c5d822SKumar Kartikeya Dwivedi 
720d63284e6SKumar Kartikeya Dwivedi static void diag_reason(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);
721d63284e6SKumar Kartikeya Dwivedi static void diag_suggestion(struct bpf_verifier_env *env, const char *fmt, ...)
722d63284e6SKumar Kartikeya Dwivedi 	__printf(2, 3);
723d63284e6SKumar Kartikeya Dwivedi 
diag_section(struct bpf_verifier_env * env,const char * title)724d63284e6SKumar Kartikeya Dwivedi static void diag_section(struct bpf_verifier_env *env, const char *title)
725d63284e6SKumar Kartikeya Dwivedi {
726d63284e6SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
727d63284e6SKumar Kartikeya Dwivedi 		return;
728d63284e6SKumar Kartikeya Dwivedi 
729d63284e6SKumar Kartikeya Dwivedi 	diag_write(env, "\n%s:\n", title);
730d63284e6SKumar Kartikeya Dwivedi }
731d63284e6SKumar Kartikeya Dwivedi 
diag_reason(struct bpf_verifier_env * env,const char * fmt,...)732d63284e6SKumar Kartikeya Dwivedi static void diag_reason(struct bpf_verifier_env *env, const char *fmt, ...)
733d63284e6SKumar Kartikeya Dwivedi {
734d63284e6SKumar Kartikeya Dwivedi 	va_list args;
735d63284e6SKumar Kartikeya Dwivedi 
736d63284e6SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
737d63284e6SKumar Kartikeya Dwivedi 		return;
738d63284e6SKumar Kartikeya Dwivedi 
739d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "Reason");
740d63284e6SKumar Kartikeya Dwivedi 
741d63284e6SKumar Kartikeya Dwivedi 	va_start(args, fmt);
742d63284e6SKumar Kartikeya Dwivedi 	diag_vprint_indented(env, fmt, args);
743d63284e6SKumar Kartikeya Dwivedi 	va_end(args);
744d63284e6SKumar Kartikeya Dwivedi }
745d63284e6SKumar Kartikeya Dwivedi 
diag_suggestion(struct bpf_verifier_env * env,const char * fmt,...)746d63284e6SKumar Kartikeya Dwivedi static void diag_suggestion(struct bpf_verifier_env *env, const char *fmt, ...)
747d63284e6SKumar Kartikeya Dwivedi {
748d63284e6SKumar Kartikeya Dwivedi 	va_list args;
749d63284e6SKumar Kartikeya Dwivedi 
750d63284e6SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
751d63284e6SKumar Kartikeya Dwivedi 		return;
752d63284e6SKumar Kartikeya Dwivedi 
753d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "Suggestion");
754d63284e6SKumar Kartikeya Dwivedi 
755d63284e6SKumar Kartikeya Dwivedi 	va_start(args, fmt);
756d63284e6SKumar Kartikeya Dwivedi 	diag_vprint_indented(env, fmt, args);
757d63284e6SKumar Kartikeya Dwivedi 	va_end(args);
758d63284e6SKumar Kartikeya Dwivedi 	diag_write(env, "\n");
759d63284e6SKumar Kartikeya Dwivedi }
760d63284e6SKumar Kartikeya Dwivedi 
diag_print_source_annotation(struct bpf_verifier_env * env,int line_width,int indent,const char * label,const char * msg)761b9c5d822SKumar Kartikeya Dwivedi static void diag_print_source_annotation(struct bpf_verifier_env *env, int line_width, int indent,
762b9c5d822SKumar Kartikeya Dwivedi 					 const char *label, const char *msg)
763b9c5d822SKumar Kartikeya Dwivedi {
764b9c5d822SKumar Kartikeya Dwivedi 	const char *first_prefix, *next_prefix, *text;
765b9c5d822SKumar Kartikeya Dwivedi 
766b9c5d822SKumar Kartikeya Dwivedi 	indent = min_t(int, indent, max_t(int, 0, BPF_DIAG_SOURCE_LANE_WIDTH - line_width - 8));
767b9c5d822SKumar Kartikeya Dwivedi 	text = bpf_diag_fmt(env, "%s: %s", label, msg);
768b9c5d822SKumar Kartikeya Dwivedi 	first_prefix = bpf_diag_fmt(env, "  %*s | %*s^-- ", line_width + 4, "", indent, "");
769b9c5d822SKumar Kartikeya Dwivedi 	next_prefix = bpf_diag_fmt(env, "  %*s | %*s    ", line_width + 4, "", indent, "");
770b9c5d822SKumar Kartikeya Dwivedi 
771b9c5d822SKumar Kartikeya Dwivedi 	diag_print_wrapped_prefixed(env, first_prefix, next_prefix, text);
772b9c5d822SKumar Kartikeya Dwivedi }
773b9c5d822SKumar Kartikeya Dwivedi 
diag_print_insn_context(struct bpf_verifier_env * env,u32 insn_idx,struct disasm_line * disasm_lines)774b9c5d822SKumar Kartikeya Dwivedi static void diag_print_insn_context(struct bpf_verifier_env *env, u32 insn_idx,
775b9c5d822SKumar Kartikeya Dwivedi 				    struct disasm_line *disasm_lines)
776b9c5d822SKumar Kartikeya Dwivedi {
777b9c5d822SKumar Kartikeya Dwivedi 	int insn_width = diag_line_width(env->prog->len ? env->prog->len - 1 : 0);
778b9c5d822SKumar Kartikeya Dwivedi 	int i;
779b9c5d822SKumar Kartikeya Dwivedi 
780b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
781b9c5d822SKumar Kartikeya Dwivedi 		int row = i - BPF_DIAG_CONTEXT;
782b9c5d822SKumar Kartikeya Dwivedi 
783b9c5d822SKumar Kartikeya Dwivedi 		format_disasm_line(env, insn_idx + row, &disasm_lines[i]);
784b9c5d822SKumar Kartikeya Dwivedi 	}
785b9c5d822SKumar Kartikeya Dwivedi 
786b9c5d822SKumar Kartikeya Dwivedi 	diag_write(env, "  Instruction context:\n");
787b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
788b9c5d822SKumar Kartikeya Dwivedi 		struct disasm_line *line = &disasm_lines[i];
789b9c5d822SKumar Kartikeya Dwivedi 
790b9c5d822SKumar Kartikeya Dwivedi 		if (line->valid)
791b9c5d822SKumar Kartikeya Dwivedi 			diag_write(env, "  %s%*d | %s\n",
792b9c5d822SKumar Kartikeya Dwivedi 				   line->idx == insn_idx ? ">>> " : "    ",
793b9c5d822SKumar Kartikeya Dwivedi 				   insn_width, line->idx, line->text);
794b9c5d822SKumar Kartikeya Dwivedi 	}
795b9c5d822SKumar Kartikeya Dwivedi }
796b9c5d822SKumar Kartikeya Dwivedi 
bpf_diag_source(struct bpf_verifier_env * env,u32 insn_idx,const char * label,const char * fmt,...)797b9c5d822SKumar Kartikeya Dwivedi static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label,
798b9c5d822SKumar Kartikeya Dwivedi 			    const char *fmt, ...)
799b9c5d822SKumar Kartikeya Dwivedi {
800b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag_scratch *scratch;
801b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source *source_lines;
802b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_line *disasm_lines;
803b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source src = {};
804b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_mark mark;
805b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_line_info *linfo;
806b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_subprog_info *subprog;
807b9c5d822SKumar Kartikeya Dwivedi 	struct btf *btf = env->prog->aux->btf;
808b9c5d822SKumar Kartikeya Dwivedi 	char *source_lane;
809b9c5d822SKumar Kartikeya Dwivedi 	const char *msg;
810b9c5d822SKumar Kartikeya Dwivedi 	const char *func;
811b9c5d822SKumar Kartikeya Dwivedi 	int start_line, end_line, width, indent, subprogno, linfo_start, linfo_end, i;
812b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
813b9c5d822SKumar Kartikeya Dwivedi 
814b9c5d822SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
815b9c5d822SKumar Kartikeya Dwivedi 		return;
816b9c5d822SKumar Kartikeya Dwivedi 	if (!env->diag)
817b9c5d822SKumar Kartikeya Dwivedi 		return;
818b9c5d822SKumar Kartikeya Dwivedi 
819b9c5d822SKumar Kartikeya Dwivedi 	mark = diag_fmt_save(env);
820b9c5d822SKumar Kartikeya Dwivedi 	label = label ?: "note";
821b9c5d822SKumar Kartikeya Dwivedi 	scratch = &env->diag->scratch;
822b9c5d822SKumar Kartikeya Dwivedi 	source_lines = scratch->source_lines;
823b9c5d822SKumar Kartikeya Dwivedi 	disasm_lines = scratch->disasm_lines;
824b9c5d822SKumar Kartikeya Dwivedi 	memset(source_lines, 0, sizeof(scratch->source_lines));
825b9c5d822SKumar Kartikeya Dwivedi 	memset(disasm_lines, 0, sizeof(scratch->disasm_lines));
826b9c5d822SKumar Kartikeya Dwivedi 
827b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
828b9c5d822SKumar Kartikeya Dwivedi 	msg = bpf_diag_vfmt(env, fmt, args);
829b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
830b9c5d822SKumar Kartikeya Dwivedi 	if (!*msg)
831b9c5d822SKumar Kartikeya Dwivedi 		msg = "<failed to allocate diagnostic text>";
832b9c5d822SKumar Kartikeya Dwivedi 
833b9c5d822SKumar Kartikeya Dwivedi 	linfo = bpf_find_linfo(env->prog, insn_idx);
834b9c5d822SKumar Kartikeya Dwivedi 	if (btf && linfo)
835b9c5d822SKumar Kartikeya Dwivedi 		bpf_get_linfo_source(btf, linfo, &src);
836*6bd520a6SKumar Kartikeya Dwivedi 	if (!src.file || !*src.file) {
837b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  insn %u\n", insn_idx);
838*6bd520a6SKumar Kartikeya Dwivedi 		goto out_annotation;
839b9c5d822SKumar Kartikeya Dwivedi 	}
840b9c5d822SKumar Kartikeya Dwivedi 
841b9c5d822SKumar Kartikeya Dwivedi 	subprog = bpf_find_containing_subprog(env, insn_idx);
842b9c5d822SKumar Kartikeya Dwivedi 	subprogno = subprog ? subprog - env->subprog_info : -ENOENT;
843b9c5d822SKumar Kartikeya Dwivedi 	func = subprogno >= 0 ? bpf_subprog_name(env, subprogno) : NULL;
844b9c5d822SKumar Kartikeya Dwivedi 	if (func && *func)
845b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s @ %s:%d:%d\n", func, src.file, src.line_num, src.line_col);
846b9c5d822SKumar Kartikeya Dwivedi 	else
847b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s:%d:%d\n", src.file, src.line_num, src.line_col);
848*6bd520a6SKumar Kartikeya Dwivedi 	if (!src.line || !*src.line)
849*6bd520a6SKumar Kartikeya Dwivedi 		goto out_annotation;
850b9c5d822SKumar Kartikeya Dwivedi 
851b9c5d822SKumar Kartikeya Dwivedi 	start_line = src.line_num - BPF_DIAG_CONTEXT;
852b9c5d822SKumar Kartikeya Dwivedi 	end_line = src.line_num + BPF_DIAG_CONTEXT;
853b9c5d822SKumar Kartikeya Dwivedi 	width = diag_line_width(end_line);
854b9c5d822SKumar Kartikeya Dwivedi 	indent = diag_line_indent(src.line);
855b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++)
856b9c5d822SKumar Kartikeya Dwivedi 		source_lines[i].line_num = start_line + i;
857b9c5d822SKumar Kartikeya Dwivedi 
858b9c5d822SKumar Kartikeya Dwivedi 	linfo = env->prog->aux->linfo;
859b9c5d822SKumar Kartikeya Dwivedi 	linfo_start = subprog ? subprog->linfo_idx : 0;
860b9c5d822SKumar Kartikeya Dwivedi 	linfo_end = subprogno >= 0 && subprogno + 1 < env->subprog_cnt ?
861b9c5d822SKumar Kartikeya Dwivedi 		    env->subprog_info[subprogno + 1].linfo_idx : env->prog->aux->nr_linfo;
862b9c5d822SKumar Kartikeya Dwivedi 	for (i = linfo_start; i < linfo_end; i++) {
863b9c5d822SKumar Kartikeya Dwivedi 		struct bpf_linfo_source line_src;
864b9c5d822SKumar Kartikeya Dwivedi 		int idx;
865b9c5d822SKumar Kartikeya Dwivedi 
866b9c5d822SKumar Kartikeya Dwivedi 		bpf_get_linfo_source(btf, &linfo[i], &line_src);
867b9c5d822SKumar Kartikeya Dwivedi 		if (line_src.file_name_off != src.file_name_off ||
868b9c5d822SKumar Kartikeya Dwivedi 		    line_src.line_num < start_line || line_src.line_num > end_line ||
869b9c5d822SKumar Kartikeya Dwivedi 		    !line_src.line || !*line_src.line)
870b9c5d822SKumar Kartikeya Dwivedi 			continue;
871b9c5d822SKumar Kartikeya Dwivedi 
872b9c5d822SKumar Kartikeya Dwivedi 		idx = line_src.line_num - start_line;
873b9c5d822SKumar Kartikeya Dwivedi 		if (!source_lines[idx].line)
874b9c5d822SKumar Kartikeya Dwivedi 			source_lines[idx] = line_src;
875b9c5d822SKumar Kartikeya Dwivedi 	}
876b9c5d822SKumar Kartikeya Dwivedi 
877b9c5d822SKumar Kartikeya Dwivedi 	diag_write(env, "  Source context:\n");
878b9c5d822SKumar Kartikeya Dwivedi 	source_lane = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE);
879b9c5d822SKumar Kartikeya Dwivedi 	if (!source_lane)
880b9c5d822SKumar Kartikeya Dwivedi 		goto out_restore;
881b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
882b9c5d822SKumar Kartikeya Dwivedi 		const char *source_prefix;
883b9c5d822SKumar Kartikeya Dwivedi 
884b9c5d822SKumar Kartikeya Dwivedi 		source_prefix = source_lines[i].line_num == src.line_num ? ">>> " : "    ";
885b9c5d822SKumar Kartikeya Dwivedi 		diag_format_source_lane(source_lane, BPF_DIAG_FMT_BUF_SIZE, source_prefix, width,
886b9c5d822SKumar Kartikeya Dwivedi 					source_lines[i].line_num, source_lines[i].line);
887b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s\n", source_lane);
888b9c5d822SKumar Kartikeya Dwivedi 		if (source_lines[i].line_num == src.line_num)
889b9c5d822SKumar Kartikeya Dwivedi 			diag_print_source_annotation(env, width, indent, label, msg);
890b9c5d822SKumar Kartikeya Dwivedi 	}
891b9c5d822SKumar Kartikeya Dwivedi 	diag_print_insn_context(env, insn_idx, disasm_lines);
892*6bd520a6SKumar Kartikeya Dwivedi 	goto out_restore;
893b9c5d822SKumar Kartikeya Dwivedi 
894*6bd520a6SKumar Kartikeya Dwivedi out_annotation:
895*6bd520a6SKumar Kartikeya Dwivedi 	diag_print_source_annotation(env, 0, 0, label, msg);
896*6bd520a6SKumar Kartikeya Dwivedi 	diag_print_insn_context(env, insn_idx, disasm_lines);
897b9c5d822SKumar Kartikeya Dwivedi out_restore:
898b9c5d822SKumar Kartikeya Dwivedi 	diag_fmt_restore(env, mark);
899b9c5d822SKumar Kartikeya Dwivedi }
900daf82487SKumar Kartikeya Dwivedi 
diag_current_frame(const struct bpf_verifier_env * env)901d63284e6SKumar Kartikeya Dwivedi static const struct bpf_func_state *diag_current_frame(const struct bpf_verifier_env *env)
902d63284e6SKumar Kartikeya Dwivedi {
903d63284e6SKumar Kartikeya Dwivedi 	return env->cur_state->frame[env->cur_state->curframe];
904d63284e6SKumar Kartikeya Dwivedi }
905d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_register_type(struct bpf_verifier_env * env,u32 insn_idx,int regno,const char * problem,const char * reason,const char * suggestion)906d63284e6SKumar Kartikeya Dwivedi void bpf_diag_register_type(struct bpf_verifier_env *env, u32 insn_idx, int regno,
907d63284e6SKumar Kartikeya Dwivedi 			    const char *problem, const char *reason, const char *suggestion)
908d63284e6SKumar Kartikeya Dwivedi {
909d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
910d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
911d63284e6SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_REG,
912d63284e6SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
913d63284e6SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
914d63284e6SKumar Kartikeya Dwivedi 		.regno = regno,
915d63284e6SKumar Kartikeya Dwivedi 	};
916d63284e6SKumar Kartikeya Dwivedi 
917d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_header(env, REGISTER_TYPE_SAFETY, problem);
918d63284e6SKumar Kartikeya Dwivedi 	diag_reason(env, "%s", reason);
919d63284e6SKumar Kartikeya Dwivedi 
920d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "At");
921d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s", problem);
922d63284e6SKumar Kartikeya Dwivedi 
923d63284e6SKumar Kartikeya Dwivedi 	if (regno >= 0)
924d63284e6SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
925d63284e6SKumar Kartikeya Dwivedi 
926d63284e6SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
927d63284e6SKumar Kartikeya Dwivedi }
928d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_reg_type_plain(struct bpf_verifier_env * env,enum bpf_reg_type type)929d63284e6SKumar Kartikeya Dwivedi const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_type type)
930d63284e6SKumar Kartikeya Dwivedi {
931d63284e6SKumar Kartikeya Dwivedi 	switch (base_type(type)) {
932d63284e6SKumar Kartikeya Dwivedi 	case NOT_INIT:
933d63284e6SKumar Kartikeya Dwivedi 		return "an uninitialized value";
934d63284e6SKumar Kartikeya Dwivedi 	case SCALAR_VALUE:
935d63284e6SKumar Kartikeya Dwivedi 		return "an integer scalar";
936d63284e6SKumar Kartikeya Dwivedi 	case PTR_TO_CTX:
937d63284e6SKumar Kartikeya Dwivedi 		return "a context pointer";
938d63284e6SKumar Kartikeya Dwivedi 	case PTR_TO_STACK:
939d63284e6SKumar Kartikeya Dwivedi 		return "a stack pointer";
940d63284e6SKumar Kartikeya Dwivedi 	case PTR_TO_MAP_VALUE:
941d63284e6SKumar Kartikeya Dwivedi 		if (type_may_be_null(type))
942d63284e6SKumar Kartikeya Dwivedi 			return "a nullable map value pointer";
943d63284e6SKumar Kartikeya Dwivedi 		return "a map value pointer";
944d63284e6SKumar Kartikeya Dwivedi 	case PTR_TO_MEM:
945d63284e6SKumar Kartikeya Dwivedi 		if (type_may_be_null(type))
946d63284e6SKumar Kartikeya Dwivedi 			return "a nullable memory pointer";
947d63284e6SKumar Kartikeya Dwivedi 		return "a memory pointer";
948d63284e6SKumar Kartikeya Dwivedi 	case PTR_TO_BTF_ID:
949d63284e6SKumar Kartikeya Dwivedi 		if (type_may_be_null(type))
950d63284e6SKumar Kartikeya Dwivedi 			return "a nullable kernel object pointer";
951d63284e6SKumar Kartikeya Dwivedi 		if (type_is_non_owning_ref(type))
952d63284e6SKumar Kartikeya Dwivedi 			return "a borrowed allocated object pointer";
953d63284e6SKumar Kartikeya Dwivedi 		if (type_is_ptr_alloc_obj(type))
954d63284e6SKumar Kartikeya Dwivedi 			return "an owned allocated object pointer";
955d63284e6SKumar Kartikeya Dwivedi 		if (type_flag(type) & PTR_UNTRUSTED)
956d63284e6SKumar Kartikeya Dwivedi 			return "an untrusted kernel object pointer";
957d63284e6SKumar Kartikeya Dwivedi 		return "a kernel object pointer";
958d63284e6SKumar Kartikeya Dwivedi 	default:
959d63284e6SKumar Kartikeya Dwivedi 		return reg_type_str(env, type);
960d63284e6SKumar Kartikeya Dwivedi 	}
961d63284e6SKumar Kartikeya Dwivedi }
962d63284e6SKumar Kartikeya Dwivedi 
diag_arg_ordinal(int argno)963d63284e6SKumar Kartikeya Dwivedi static const char *diag_arg_ordinal(int argno)
964d63284e6SKumar Kartikeya Dwivedi {
965d63284e6SKumar Kartikeya Dwivedi 	switch (argno) {
966d63284e6SKumar Kartikeya Dwivedi 	case 1:
967d63284e6SKumar Kartikeya Dwivedi 		return "first";
968d63284e6SKumar Kartikeya Dwivedi 	case 2:
969d63284e6SKumar Kartikeya Dwivedi 		return "second";
970d63284e6SKumar Kartikeya Dwivedi 	case 3:
971d63284e6SKumar Kartikeya Dwivedi 		return "third";
972d63284e6SKumar Kartikeya Dwivedi 	case 4:
973d63284e6SKumar Kartikeya Dwivedi 		return "fourth";
974d63284e6SKumar Kartikeya Dwivedi 	case 5:
975d63284e6SKumar Kartikeya Dwivedi 		return "fifth";
976d63284e6SKumar Kartikeya Dwivedi 	case 6:
977d63284e6SKumar Kartikeya Dwivedi 		return "sixth";
978d63284e6SKumar Kartikeya Dwivedi 	case 7:
979d63284e6SKumar Kartikeya Dwivedi 		return "seventh";
980d63284e6SKumar Kartikeya Dwivedi 	case 8:
981d63284e6SKumar Kartikeya Dwivedi 		return "eighth";
982d63284e6SKumar Kartikeya Dwivedi 	case 9:
983d63284e6SKumar Kartikeya Dwivedi 		return "ninth";
984d63284e6SKumar Kartikeya Dwivedi 	case 10:
985d63284e6SKumar Kartikeya Dwivedi 		return "tenth";
986d63284e6SKumar Kartikeya Dwivedi 	case 11:
987d63284e6SKumar Kartikeya Dwivedi 		return "eleventh";
988d63284e6SKumar Kartikeya Dwivedi 	case 12:
989d63284e6SKumar Kartikeya Dwivedi 		return "twelfth";
990d63284e6SKumar Kartikeya Dwivedi 	default:
991d63284e6SKumar Kartikeya Dwivedi 		return NULL;
992d63284e6SKumar Kartikeya Dwivedi 	}
993d63284e6SKumar Kartikeya Dwivedi }
994d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_call_type(struct bpf_verifier_env * env,u32 insn_idx,int argno,int regno,int stack_arg_slot,const char * call_name,const char * arg_name,const char * reason,const char * suggestion)99566e27273SKumar Kartikeya Dwivedi void bpf_diag_call_type(struct bpf_verifier_env *env, u32 insn_idx, int argno, int regno,
99666e27273SKumar Kartikeya Dwivedi 			int stack_arg_slot, const char *call_name, const char *arg_name,
99766e27273SKumar Kartikeya Dwivedi 			const char *reason, const char *suggestion)
99866e27273SKumar Kartikeya Dwivedi {
99966e27273SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
100066e27273SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
100166e27273SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
100266e27273SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
100366e27273SKumar Kartikeya Dwivedi 	};
100466e27273SKumar Kartikeya Dwivedi 	const char *ordinal = diag_arg_ordinal(argno);
100566e27273SKumar Kartikeya Dwivedi 	const char *arg_desc;
100666e27273SKumar Kartikeya Dwivedi 	bool print_history = true;
100766e27273SKumar Kartikeya Dwivedi 
100866e27273SKumar Kartikeya Dwivedi 	if (regno >= 0) {
100966e27273SKumar Kartikeya Dwivedi 		opts.scope = BPF_DIAG_HISTORY_SCOPE_REG;
101066e27273SKumar Kartikeya Dwivedi 		opts.regno = regno;
101166e27273SKumar Kartikeya Dwivedi 	} else if (stack_arg_slot >= 0) {
101266e27273SKumar Kartikeya Dwivedi 		opts.scope = BPF_DIAG_HISTORY_SCOPE_STACK_ARG;
101366e27273SKumar Kartikeya Dwivedi 		opts.stack_arg_slot = stack_arg_slot;
101466e27273SKumar Kartikeya Dwivedi 	} else {
101566e27273SKumar Kartikeya Dwivedi 		print_history = false;
101666e27273SKumar Kartikeya Dwivedi 	}
101766e27273SKumar Kartikeya Dwivedi 
101866e27273SKumar Kartikeya Dwivedi 	if (ordinal && arg_name)
101966e27273SKumar Kartikeya Dwivedi 		arg_desc = bpf_diag_fmt(env, "%s argument (%s)", ordinal, arg_name);
102066e27273SKumar Kartikeya Dwivedi 	else if (ordinal)
102166e27273SKumar Kartikeya Dwivedi 		arg_desc = bpf_diag_fmt(env, "%s argument", ordinal);
102266e27273SKumar Kartikeya Dwivedi 	else if (arg_name)
102366e27273SKumar Kartikeya Dwivedi 		arg_desc = bpf_diag_fmt(env, "argument %s", arg_name);
102466e27273SKumar Kartikeya Dwivedi 	else
102566e27273SKumar Kartikeya Dwivedi 		arg_desc = "argument";
102666e27273SKumar Kartikeya Dwivedi 
102766e27273SKumar Kartikeya Dwivedi 	bpf_diag_header(env, CALL_TYPE_SAFETY, "invalid call argument");
102866e27273SKumar Kartikeya Dwivedi 	diag_reason(env, "The %s to %s does not satisfy the verifier contract: %s.",
102966e27273SKumar Kartikeya Dwivedi 		    arg_desc, call_name, reason);
103066e27273SKumar Kartikeya Dwivedi 
103166e27273SKumar Kartikeya Dwivedi 	diag_section(env, "At");
103266e27273SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "invalid %s for %s", arg_desc, call_name);
103366e27273SKumar Kartikeya Dwivedi 
103466e27273SKumar Kartikeya Dwivedi 	if (print_history)
103566e27273SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
103666e27273SKumar Kartikeya Dwivedi 
103766e27273SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
103866e27273SKumar Kartikeya Dwivedi }
103966e27273SKumar Kartikeya Dwivedi 
diag_context_constraint(enum bpf_diag_context_kind kind)104099a6a288SKumar Kartikeya Dwivedi static const char *diag_context_constraint(enum bpf_diag_context_kind kind)
104199a6a288SKumar Kartikeya Dwivedi {
104299a6a288SKumar Kartikeya Dwivedi 	switch (kind) {
104399a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_RCU:
104499a6a288SKumar Kartikeya Dwivedi 		return "RCU read-side critical sections cannot call operations that may sleep";
104599a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_PREEMPT:
104699a6a288SKumar Kartikeya Dwivedi 		return "preemption-disabled code cannot call operations that may sleep";
104799a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_IRQ:
104899a6a288SKumar Kartikeya Dwivedi 		return "IRQ-disabled code cannot call operations that may sleep";
104999a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_LOCK:
105099a6a288SKumar Kartikeya Dwivedi 		return "code holding a BPF spin lock cannot call operations that may sleep";
105199a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_NONE:
105299a6a288SKumar Kartikeya Dwivedi 	default:
105399a6a288SKumar Kartikeya Dwivedi 		return NULL;
105499a6a288SKumar Kartikeya Dwivedi 	}
105599a6a288SKumar Kartikeya Dwivedi }
105699a6a288SKumar Kartikeya Dwivedi 
diag_active_context(struct bpf_verifier_env * env,u32 depth,const char * context)105799a6a288SKumar Kartikeya Dwivedi static const char *diag_active_context(struct bpf_verifier_env *env, u32 depth,
105899a6a288SKumar Kartikeya Dwivedi 				       const char *context)
105999a6a288SKumar Kartikeya Dwivedi {
106099a6a288SKumar Kartikeya Dwivedi 	if (depth == 1)
106199a6a288SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "an active %s (depth 1)", context);
106299a6a288SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env, "%u active %ss (depth %u)", depth, context, depth);
106399a6a288SKumar Kartikeya Dwivedi }
106499a6a288SKumar Kartikeya Dwivedi 
diag_context_depth(struct bpf_verifier_env * env,enum bpf_diag_context_kind kind)106599a6a288SKumar Kartikeya Dwivedi static u32 diag_context_depth(struct bpf_verifier_env *env, enum bpf_diag_context_kind kind)
106699a6a288SKumar Kartikeya Dwivedi {
106799a6a288SKumar Kartikeya Dwivedi 	switch (kind) {
106899a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_RCU:
106999a6a288SKumar Kartikeya Dwivedi 		return env->cur_state->active_rcu_locks;
107099a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_PREEMPT:
107199a6a288SKumar Kartikeya Dwivedi 		return env->cur_state->active_preempt_locks;
107299a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_IRQ:
107399a6a288SKumar Kartikeya Dwivedi 		return bpf_diag_irq_depth(env->cur_state);
107499a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_LOCK:
107599a6a288SKumar Kartikeya Dwivedi 		return env->cur_state->active_locks;
107699a6a288SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_NONE:
107799a6a288SKumar Kartikeya Dwivedi 	default:
107899a6a288SKumar Kartikeya Dwivedi 		return 0;
107999a6a288SKumar Kartikeya Dwivedi 	}
108099a6a288SKumar Kartikeya Dwivedi }
108199a6a288SKumar Kartikeya Dwivedi 
bpf_diag_ctx_forbidden(struct bpf_verifier_env * env,u32 insn_idx,const char * operation,const char * suggestion)108299a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx,
108399a6a288SKumar Kartikeya Dwivedi 			    const char *operation, const char *suggestion)
108499a6a288SKumar Kartikeya Dwivedi {
108599a6a288SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts;
108699a6a288SKumar Kartikeya Dwivedi 	enum bpf_diag_context_kind ctx_kind;
108799a6a288SKumar Kartikeya Dwivedi 	const char *constraint, *context;
108899a6a288SKumar Kartikeya Dwivedi 	u32 depth;
108999a6a288SKumar Kartikeya Dwivedi 
109099a6a288SKumar Kartikeya Dwivedi 	if (env->cur_state->active_rcu_locks)
109199a6a288SKumar Kartikeya Dwivedi 		ctx_kind = BPF_DIAG_CONTEXT_RCU;
109299a6a288SKumar Kartikeya Dwivedi 	else if (env->cur_state->active_preempt_locks)
109399a6a288SKumar Kartikeya Dwivedi 		ctx_kind = BPF_DIAG_CONTEXT_PREEMPT;
109499a6a288SKumar Kartikeya Dwivedi 	else if (env->cur_state->active_irq_id)
109599a6a288SKumar Kartikeya Dwivedi 		ctx_kind = BPF_DIAG_CONTEXT_IRQ;
109699a6a288SKumar Kartikeya Dwivedi 	else if (env->cur_state->active_locks)
109799a6a288SKumar Kartikeya Dwivedi 		ctx_kind = BPF_DIAG_CONTEXT_LOCK;
109899a6a288SKumar Kartikeya Dwivedi 	else
109999a6a288SKumar Kartikeya Dwivedi 		ctx_kind = BPF_DIAG_CONTEXT_NONE;
110099a6a288SKumar Kartikeya Dwivedi 
110199a6a288SKumar Kartikeya Dwivedi 	depth = diag_context_depth(env, ctx_kind);
110299a6a288SKumar Kartikeya Dwivedi 	opts = (struct bpf_diag_history_opts) {
110399a6a288SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT,
110499a6a288SKumar Kartikeya Dwivedi 		.ctx_kind = ctx_kind,
110599a6a288SKumar Kartikeya Dwivedi 		.ctx_depth = depth,
110699a6a288SKumar Kartikeya Dwivedi 	};
110799a6a288SKumar Kartikeya Dwivedi 	constraint = diag_context_constraint(ctx_kind);
110899a6a288SKumar Kartikeya Dwivedi 	context = diag_context_name(ctx_kind);
110999a6a288SKumar Kartikeya Dwivedi 
111099a6a288SKumar Kartikeya Dwivedi 	bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY,
111199a6a288SKumar Kartikeya Dwivedi 			"operation is not allowed in this context");
111299a6a288SKumar Kartikeya Dwivedi 	if (constraint) {
111399a6a288SKumar Kartikeya Dwivedi 		if (depth) {
111499a6a288SKumar Kartikeya Dwivedi 			diag_reason(
111599a6a288SKumar Kartikeya Dwivedi 				env, "The operation %s cannot be used in %s because %s. This path is still inside %s.",
111699a6a288SKumar Kartikeya Dwivedi 				operation, context, constraint, diag_active_context(env, depth, context));
111799a6a288SKumar Kartikeya Dwivedi 		} else {
111899a6a288SKumar Kartikeya Dwivedi 			diag_reason(env, "The operation %s cannot be used in %s because %s.",
111999a6a288SKumar Kartikeya Dwivedi 				    operation, context, constraint);
112099a6a288SKumar Kartikeya Dwivedi 		}
112199a6a288SKumar Kartikeya Dwivedi 	} else {
112299a6a288SKumar Kartikeya Dwivedi 		diag_reason(env, "The operation %s cannot be used in %s.", operation,
112399a6a288SKumar Kartikeya Dwivedi 			    context);
112499a6a288SKumar Kartikeya Dwivedi 	}
112599a6a288SKumar Kartikeya Dwivedi 
112699a6a288SKumar Kartikeya Dwivedi 	diag_section(env, "At");
112799a6a288SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s is not allowed in %s", operation,
112899a6a288SKumar Kartikeya Dwivedi 			context);
112999a6a288SKumar Kartikeya Dwivedi 
113099a6a288SKumar Kartikeya Dwivedi 	if (ctx_kind != BPF_DIAG_CONTEXT_NONE)
113199a6a288SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
113299a6a288SKumar Kartikeya Dwivedi 
113399a6a288SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
113499a6a288SKumar Kartikeya Dwivedi }
113599a6a288SKumar Kartikeya Dwivedi 
bpf_diag_ctx_active(struct bpf_verifier_env * env,u32 insn_idx,const char * operation,enum bpf_diag_context_kind ctx_kind,const char * suggestion)113699a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_active(struct bpf_verifier_env *env, u32 insn_idx, const char *operation,
113799a6a288SKumar Kartikeya Dwivedi 			 enum bpf_diag_context_kind ctx_kind, const char *suggestion)
113899a6a288SKumar Kartikeya Dwivedi {
113999a6a288SKumar Kartikeya Dwivedi 	u32 depth = diag_context_depth(env, ctx_kind);
114099a6a288SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
114199a6a288SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT,
114299a6a288SKumar Kartikeya Dwivedi 		.ctx_kind = ctx_kind,
114399a6a288SKumar Kartikeya Dwivedi 		.ctx_depth = depth,
114499a6a288SKumar Kartikeya Dwivedi 	};
114599a6a288SKumar Kartikeya Dwivedi 	const char *context = diag_context_name(ctx_kind);
114699a6a288SKumar Kartikeya Dwivedi 
114799a6a288SKumar Kartikeya Dwivedi 	bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY,
114899a6a288SKumar Kartikeya Dwivedi 			"operation is not allowed in this context");
114999a6a288SKumar Kartikeya Dwivedi 	diag_reason(
115099a6a288SKumar Kartikeya Dwivedi 		env, "The operation %s cannot be used while this path is still inside %s. Leave the region before this operation.",
115199a6a288SKumar Kartikeya Dwivedi 		operation, diag_active_context(env, depth, context));
115299a6a288SKumar Kartikeya Dwivedi 
115399a6a288SKumar Kartikeya Dwivedi 	diag_section(env, "At");
115499a6a288SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s is not allowed before leaving %s",
115599a6a288SKumar Kartikeya Dwivedi 			operation, context);
115699a6a288SKumar Kartikeya Dwivedi 
115799a6a288SKumar Kartikeya Dwivedi 	diag_print_history(env, &opts);
115899a6a288SKumar Kartikeya Dwivedi 
115999a6a288SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
116099a6a288SKumar Kartikeya Dwivedi }
116199a6a288SKumar Kartikeya Dwivedi 
bpf_diag_ctx_required(struct bpf_verifier_env * env,u32 insn_idx,const char * operation,enum bpf_diag_context_kind ctx_kind,const char * suggestion)116299a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_required(struct bpf_verifier_env *env, u32 insn_idx, const char *operation,
116399a6a288SKumar Kartikeya Dwivedi 			   enum bpf_diag_context_kind ctx_kind, const char *suggestion)
116499a6a288SKumar Kartikeya Dwivedi {
116599a6a288SKumar Kartikeya Dwivedi 	const char *context = diag_context_name(ctx_kind);
116699a6a288SKumar Kartikeya Dwivedi 
116799a6a288SKumar Kartikeya Dwivedi 	bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, "required context is not active");
116899a6a288SKumar Kartikeya Dwivedi 	diag_reason(env, "The operation %s requires an active %s, but this path is outside one.",
116999a6a288SKumar Kartikeya Dwivedi 		    operation, context);
117099a6a288SKumar Kartikeya Dwivedi 
117199a6a288SKumar Kartikeya Dwivedi 	diag_section(env, "At");
117299a6a288SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s requires %s", operation, context);
117399a6a288SKumar Kartikeya Dwivedi 
117499a6a288SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
117599a6a288SKumar Kartikeya Dwivedi }
117699a6a288SKumar Kartikeya Dwivedi 
bpf_diag_ctx_underflow(struct bpf_verifier_env * env,u32 insn_idx,const char * operation,enum bpf_diag_context_kind ctx_kind,const char * suggestion)117799a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_underflow(struct bpf_verifier_env *env, u32 insn_idx,
117899a6a288SKumar Kartikeya Dwivedi 			    const char *operation, enum bpf_diag_context_kind ctx_kind,
117999a6a288SKumar Kartikeya Dwivedi 			    const char *suggestion)
118099a6a288SKumar Kartikeya Dwivedi {
118199a6a288SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
118299a6a288SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT,
118399a6a288SKumar Kartikeya Dwivedi 		.ctx_kind = ctx_kind,
118499a6a288SKumar Kartikeya Dwivedi 	};
118599a6a288SKumar Kartikeya Dwivedi 	const char *context = diag_context_name(ctx_kind);
118699a6a288SKumar Kartikeya Dwivedi 
118799a6a288SKumar Kartikeya Dwivedi 	bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, "unmatched context exit");
118899a6a288SKumar Kartikeya Dwivedi 	diag_reason(
118999a6a288SKumar Kartikeya Dwivedi 		env, "The operation %s tries to leave %s, but this path has no active %s to leave. The current depth is 0.",
119099a6a288SKumar Kartikeya Dwivedi 		operation, context, context);
119199a6a288SKumar Kartikeya Dwivedi 
119299a6a288SKumar Kartikeya Dwivedi 	diag_section(env, "At");
119399a6a288SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s has no matching enter on this path",
119499a6a288SKumar Kartikeya Dwivedi 			operation);
119599a6a288SKumar Kartikeya Dwivedi 
119699a6a288SKumar Kartikeya Dwivedi 	diag_print_history(env, &opts);
119799a6a288SKumar Kartikeya Dwivedi 
119899a6a288SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
119999a6a288SKumar Kartikeya Dwivedi }
120099a6a288SKumar Kartikeya Dwivedi 
bpf_diag_program_structure(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * suggestion,const char * reason_fmt,...)1201a8f42783SKumar Kartikeya Dwivedi void bpf_diag_program_structure(struct bpf_verifier_env *env, u32 insn_idx,
1202a8f42783SKumar Kartikeya Dwivedi 				const char *problem, const char *suggestion,
1203a8f42783SKumar Kartikeya Dwivedi 				const char *reason_fmt, ...)
1204a8f42783SKumar Kartikeya Dwivedi {
1205a8f42783SKumar Kartikeya Dwivedi 	va_list args;
1206a8f42783SKumar Kartikeya Dwivedi 
1207a8f42783SKumar Kartikeya Dwivedi 	bpf_diag_header(env, PROGRAM_STRUCTURE, problem);
1208a8f42783SKumar Kartikeya Dwivedi 	diag_section(env, "Reason");
1209a8f42783SKumar Kartikeya Dwivedi 
1210a8f42783SKumar Kartikeya Dwivedi 	va_start(args, reason_fmt);
1211a8f42783SKumar Kartikeya Dwivedi 	diag_vprint_indented(env, reason_fmt, args);
1212a8f42783SKumar Kartikeya Dwivedi 	va_end(args);
1213a8f42783SKumar Kartikeya Dwivedi 
1214a8f42783SKumar Kartikeya Dwivedi 	diag_section(env, "At");
1215a8f42783SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s", problem);
1216a8f42783SKumar Kartikeya Dwivedi 
1217a8f42783SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
1218a8f42783SKumar Kartikeya Dwivedi }
1219ac545b00SKumar Kartikeya Dwivedi 
bpf_diag_policy(struct bpf_verifier_env * env,u32 insn_idx,const char * operation,const char * reason,const char * suggestion)1220ac545b00SKumar Kartikeya Dwivedi void bpf_diag_policy(struct bpf_verifier_env *env, u32 insn_idx, const char *operation,
1221ac545b00SKumar Kartikeya Dwivedi 		     const char *reason, const char *suggestion)
1222ac545b00SKumar Kartikeya Dwivedi {
1223ac545b00SKumar Kartikeya Dwivedi 	bpf_diag_header(env, POLICY, "operation is not allowed");
1224ac545b00SKumar Kartikeya Dwivedi 	diag_reason(env, "The %s is not allowed: %s.", operation, reason);
1225ac545b00SKumar Kartikeya Dwivedi 
1226ac545b00SKumar Kartikeya Dwivedi 	diag_section(env, "At");
1227ac545b00SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "policy check failed for %s", operation);
1228ac545b00SKumar Kartikeya Dwivedi 
1229ac545b00SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
1230ac545b00SKumar Kartikeya Dwivedi }
1231ac545b00SKumar Kartikeya Dwivedi 
bpf_diag_invalid_deref(struct bpf_verifier_env * env,u32 insn_idx,int regno,const char * reg_name,const struct bpf_reg_state * reg,enum bpf_diag_invalid_deref_kind kind,s64 offset)1232d63284e6SKumar Kartikeya Dwivedi void bpf_diag_invalid_deref(struct bpf_verifier_env *env, u32 insn_idx, int regno,
1233d63284e6SKumar Kartikeya Dwivedi 			    const char *reg_name, const struct bpf_reg_state *reg,
1234d63284e6SKumar Kartikeya Dwivedi 			    enum bpf_diag_invalid_deref_kind kind, s64 offset)
1235d63284e6SKumar Kartikeya Dwivedi {
1236d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
1237d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
1238d63284e6SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_REG,
1239d63284e6SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
1240d63284e6SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
1241d63284e6SKumar Kartikeya Dwivedi 		.regno = regno,
1242d63284e6SKumar Kartikeya Dwivedi 	};
1243d63284e6SKumar Kartikeya Dwivedi 	const char *type_name = bpf_diag_reg_type_plain(env, reg->type);
1244d63284e6SKumar Kartikeya Dwivedi 
1245d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_header(env, REGISTER_TYPE_SAFETY, "invalid dereference");
1246d63284e6SKumar Kartikeya Dwivedi 
1247d63284e6SKumar Kartikeya Dwivedi 	switch (kind) {
1248d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_SCALAR:
1249d63284e6SKumar Kartikeya Dwivedi 		diag_reason(env, "%s is an integer scalar here, not a pointer to memory.",
1250d63284e6SKumar Kartikeya Dwivedi 			    reg_name);
1251d63284e6SKumar Kartikeya Dwivedi 		break;
1252d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_NULLABLE_PTR:
1253d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1254d63284e6SKumar Kartikeya Dwivedi 			env, "%s may be NULL here (%s). The program could dereference NULL on this path, so the verifier cannot prove this access is safe.",
1255d63284e6SKumar Kartikeya Dwivedi 			reg_name, type_name);
1256d63284e6SKumar Kartikeya Dwivedi 		break;
1257d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_MODIFIED_PTR:
1258d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1259d63284e6SKumar Kartikeya Dwivedi 			env, "%s has offset %lld here, but this pointer type must be dereferenced in its original form.",
1260d63284e6SKumar Kartikeya Dwivedi 			reg_name, offset);
1261d63284e6SKumar Kartikeya Dwivedi 		break;
1262d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_INVALID_PTR:
1263d63284e6SKumar Kartikeya Dwivedi 	default:
1264d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1265d63284e6SKumar Kartikeya Dwivedi 			env, "%s has type %s here, which is not valid for this memory access.",
1266d63284e6SKumar Kartikeya Dwivedi 			reg_name, type_name);
1267d63284e6SKumar Kartikeya Dwivedi 		break;
1268d63284e6SKumar Kartikeya Dwivedi 	}
1269d63284e6SKumar Kartikeya Dwivedi 
1270d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "At");
1271d63284e6SKumar Kartikeya Dwivedi 	if (kind == BPF_DIAG_DEREF_MODIFIED_PTR)
1272d63284e6SKumar Kartikeya Dwivedi 		bpf_diag_source(env, insn_idx, "error",
1273d63284e6SKumar Kartikeya Dwivedi 				"dereference requires the original %s pointer", type_name);
1274d63284e6SKumar Kartikeya Dwivedi 	else
1275d63284e6SKumar Kartikeya Dwivedi 		bpf_diag_source(env, insn_idx, "error", "invalid dereference of %s (%s)",
1276d63284e6SKumar Kartikeya Dwivedi 				reg_name, type_name);
1277d63284e6SKumar Kartikeya Dwivedi 
1278d63284e6SKumar Kartikeya Dwivedi 	if (regno >= 0)
1279d63284e6SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
1280d63284e6SKumar Kartikeya Dwivedi 
1281d63284e6SKumar Kartikeya Dwivedi 	switch (kind) {
1282d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_NULLABLE_PTR:
1283d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(
1284d63284e6SKumar Kartikeya Dwivedi 			env, "Add a NULL check before the access and dereference the pointer only on the non-NULL path.");
1285d63284e6SKumar Kartikeya Dwivedi 		break;
1286d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_MODIFIED_PTR:
1287d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(
1288d63284e6SKumar Kartikeya Dwivedi 			env, "Preserve the original pointer in another register, or use only offsets this pointer type permits before dereferencing it.");
1289d63284e6SKumar Kartikeya Dwivedi 		break;
1290d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_SCALAR:
1291d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_DEREF_INVALID_PTR:
1292d63284e6SKumar Kartikeya Dwivedi 	default:
1293d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(
1294d63284e6SKumar Kartikeya Dwivedi 			env, "Preserve a pointer-valued register where needed, or reload and revalidate the pointer after scalar arithmetic, helper calls, or other operations that can invalidate it.");
1295d63284e6SKumar Kartikeya Dwivedi 		break;
1296d63284e6SKumar Kartikeya Dwivedi 	}
1297d63284e6SKumar Kartikeya Dwivedi }
1298d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_unreadable_reg(struct bpf_verifier_env * env,u32 insn_idx,int regno)1299d63284e6SKumar Kartikeya Dwivedi void bpf_diag_unreadable_reg(struct bpf_verifier_env *env, u32 insn_idx, int regno)
1300d63284e6SKumar Kartikeya Dwivedi {
1301d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
1302d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
1303d63284e6SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_REG,
1304d63284e6SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
1305d63284e6SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
1306d63284e6SKumar Kartikeya Dwivedi 		.regno = regno,
1307d63284e6SKumar Kartikeya Dwivedi 	};
1308d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_log *log = env->diag ? &env->diag->log : NULL;
1309d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
1310d63284e6SKumar Kartikeya Dwivedi 	bool invalidated = false;
1311d63284e6SKumar Kartikeya Dwivedi 	int i;
1312d63284e6SKumar Kartikeya Dwivedi 
1313d63284e6SKumar Kartikeya Dwivedi 	target = diag_reg_target(opts.frame_id, opts.frameno, regno);
1314d63284e6SKumar Kartikeya Dwivedi 	for (i = log ? log->cnt : 0; i > 0; i--) {
1315d63284e6SKumar Kartikeya Dwivedi 		const struct bpf_diag_history_event *event;
1316d63284e6SKumar Kartikeya Dwivedi 
1317d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i - 1)];
1318d63284e6SKumar Kartikeya Dwivedi 
1319d63284e6SKumar Kartikeya Dwivedi 		if (event->kind != BPF_DIAG_HISTORY_MOD ||
1320d63284e6SKumar Kartikeya Dwivedi 		    !diag_target_matches(&event->mod.target, &target))
1321d63284e6SKumar Kartikeya Dwivedi 			continue;
1322d63284e6SKumar Kartikeya Dwivedi 		invalidated = event->mod.new.type == NOT_INIT;
1323d63284e6SKumar Kartikeya Dwivedi 		break;
1324d63284e6SKumar Kartikeya Dwivedi 	}
1325d63284e6SKumar Kartikeya Dwivedi 
1326d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_header(env, REGISTER_TYPE_SAFETY, "unreadable register");
1327d63284e6SKumar Kartikeya Dwivedi 	if (invalidated)
1328d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1329d63284e6SKumar Kartikeya Dwivedi 			env, "R%d is not readable here. A previous operation invalidated this register, so the verifier cannot use it as an input.",
1330d63284e6SKumar Kartikeya Dwivedi 			regno);
1331d63284e6SKumar Kartikeya Dwivedi 	else if (log && !log->first_seq)
1332d63284e6SKumar Kartikeya Dwivedi 		diag_reason(env,
1333d63284e6SKumar Kartikeya Dwivedi 			    "R%d has never been initialized on this path, so the verifier cannot use it as an input.",
1334d63284e6SKumar Kartikeya Dwivedi 			    regno);
1335d63284e6SKumar Kartikeya Dwivedi 	else
1336d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1337d63284e6SKumar Kartikeya Dwivedi 			env, "R%d is not readable here. It may never have been initialized, or an earlier operation may have invalidated it.",
1338d63284e6SKumar Kartikeya Dwivedi 			regno);
1339d63284e6SKumar Kartikeya Dwivedi 
1340d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "At");
1341d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "R%d is not readable", regno);
1342d63284e6SKumar Kartikeya Dwivedi 
1343d63284e6SKumar Kartikeya Dwivedi 	if (regno >= 0)
1344d63284e6SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
1345d63284e6SKumar Kartikeya Dwivedi 
1346d63284e6SKumar Kartikeya Dwivedi 	if (invalidated)
1347d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(
1348d63284e6SKumar Kartikeya Dwivedi 			env, "Avoid using the register after it is invalidated, or initialize it again before this instruction.");
1349d63284e6SKumar Kartikeya Dwivedi 	else if (log && !log->first_seq)
1350d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(env, "Initialize R%d on every path before this instruction.", regno);
1351d63284e6SKumar Kartikeya Dwivedi 	else
1352d63284e6SKumar Kartikeya Dwivedi 		diag_suggestion(
1353d63284e6SKumar Kartikeya Dwivedi 			env, "Initialize the register on every path, or initialize it again after any operation that invalidates it.");
1354d63284e6SKumar Kartikeya Dwivedi }
1355d63284e6SKumar Kartikeya Dwivedi 
diag_stack_argno(u8 slot)1356d63284e6SKumar Kartikeya Dwivedi static int diag_stack_argno(u8 slot)
1357d63284e6SKumar Kartikeya Dwivedi {
1358d63284e6SKumar Kartikeya Dwivedi 	return MAX_BPF_FUNC_REG_ARGS + slot + 1;
1359d63284e6SKumar Kartikeya Dwivedi }
1360d63284e6SKumar Kartikeya Dwivedi 
diag_format_stack_arg(char * buf,size_t size,u8 slot,const char * arg_name)1361d63284e6SKumar Kartikeya Dwivedi static void diag_format_stack_arg(char *buf, size_t size, u8 slot, const char *arg_name)
1362d63284e6SKumar Kartikeya Dwivedi {
1363d63284e6SKumar Kartikeya Dwivedi 	int argno = diag_stack_argno(slot);
1364d63284e6SKumar Kartikeya Dwivedi 	const char *ordinal = diag_arg_ordinal(argno);
1365d63284e6SKumar Kartikeya Dwivedi 
1366d63284e6SKumar Kartikeya Dwivedi 	if (ordinal && arg_name)
1367d63284e6SKumar Kartikeya Dwivedi 		scnprintf(buf, size, "outgoing stack argument %u (%s argument, %s)", slot + 1,
1368d63284e6SKumar Kartikeya Dwivedi 			  ordinal, arg_name);
1369d63284e6SKumar Kartikeya Dwivedi 	else if (ordinal)
1370d63284e6SKumar Kartikeya Dwivedi 		scnprintf(buf, size, "outgoing stack argument %u (%s argument)", slot + 1, ordinal);
1371d63284e6SKumar Kartikeya Dwivedi 	else if (arg_name)
1372d63284e6SKumar Kartikeya Dwivedi 		scnprintf(buf, size, "outgoing stack argument %u (%s)", slot + 1, arg_name);
1373d63284e6SKumar Kartikeya Dwivedi 	else
1374d63284e6SKumar Kartikeya Dwivedi 		scnprintf(buf, size, "outgoing stack argument %u", slot + 1);
1375d63284e6SKumar Kartikeya Dwivedi }
1376d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_stack_arg_uninit(struct bpf_verifier_env * env,u32 insn_idx,int nargs,int stack_arg_slot,const char * callee_name,const char * arg_name)1377d63284e6SKumar Kartikeya Dwivedi void bpf_diag_stack_arg_uninit(struct bpf_verifier_env *env, u32 insn_idx, int nargs,
1378d63284e6SKumar Kartikeya Dwivedi 			       int stack_arg_slot, const char *callee_name,
1379d63284e6SKumar Kartikeya Dwivedi 			       const char *arg_name)
1380d63284e6SKumar Kartikeya Dwivedi {
1381d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
1382d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
1383d63284e6SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_STACK_ARG,
1384d63284e6SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
1385d63284e6SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
1386d63284e6SKumar Kartikeya Dwivedi 		.stack_arg_slot = stack_arg_slot,
1387d63284e6SKumar Kartikeya Dwivedi 	};
1388d63284e6SKumar Kartikeya Dwivedi 	const char *arg_buf;
1389d63284e6SKumar Kartikeya Dwivedi 
1390d63284e6SKumar Kartikeya Dwivedi 	arg_buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE);
1391d63284e6SKumar Kartikeya Dwivedi 	if (arg_buf)
1392d63284e6SKumar Kartikeya Dwivedi 		diag_format_stack_arg((char *)arg_buf, BPF_DIAG_FMT_BUF_SIZE, stack_arg_slot,
1393d63284e6SKumar Kartikeya Dwivedi 				      arg_name);
1394d63284e6SKumar Kartikeya Dwivedi 	else
1395d63284e6SKumar Kartikeya Dwivedi 		arg_buf = "";
1396d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_header(env, REGISTER_TYPE_SAFETY, "missing stack argument");
1397d63284e6SKumar Kartikeya Dwivedi 	if (callee_name && *callee_name)
1398d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1399d63284e6SKumar Kartikeya Dwivedi 			env, "Function %s expects %d arguments, but %s is not initialized at this call.",
1400d63284e6SKumar Kartikeya Dwivedi 			callee_name, nargs, arg_buf);
1401d63284e6SKumar Kartikeya Dwivedi 	else
1402d63284e6SKumar Kartikeya Dwivedi 		diag_reason(
1403d63284e6SKumar Kartikeya Dwivedi 			env, "The callee expects %d arguments, but %s is not initialized at this call.",
1404d63284e6SKumar Kartikeya Dwivedi 			nargs, arg_buf);
1405d63284e6SKumar Kartikeya Dwivedi 
1406d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "At");
1407d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s is not initialized", arg_buf);
1408d63284e6SKumar Kartikeya Dwivedi 
1409d63284e6SKumar Kartikeya Dwivedi 	if (stack_arg_slot >= 0)
1410d63284e6SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
1411d63284e6SKumar Kartikeya Dwivedi 
1412d63284e6SKumar Kartikeya Dwivedi 	diag_suggestion(
1413d63284e6SKumar Kartikeya Dwivedi 		env, "Write the outgoing stack argument after any operation that may invalidate stored pointer values, and before making this call.");
1414d63284e6SKumar Kartikeya Dwivedi }
1415d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_memory(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * reason,const char * suggestion)14162bdc90f5SKumar Kartikeya Dwivedi void bpf_diag_memory(struct bpf_verifier_env *env, u32 insn_idx, const char *problem,
14172bdc90f5SKumar Kartikeya Dwivedi 		     const char *reason, const char *suggestion)
14182bdc90f5SKumar Kartikeya Dwivedi {
14192bdc90f5SKumar Kartikeya Dwivedi 	bpf_diag_header(env, MEMORY_SAFETY, problem);
14202bdc90f5SKumar Kartikeya Dwivedi 	diag_reason(env, "%s", reason);
14212bdc90f5SKumar Kartikeya Dwivedi 
14222bdc90f5SKumar Kartikeya Dwivedi 	diag_section(env, "At");
14232bdc90f5SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s", problem);
14242bdc90f5SKumar Kartikeya Dwivedi 
14252bdc90f5SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
14262bdc90f5SKumar Kartikeya Dwivedi }
14272bdc90f5SKumar Kartikeya Dwivedi 
bpf_diag_record_branch(struct bpf_verifier_env * env,u32 insn_idx,bool cond_true)1428daf82487SKumar Kartikeya Dwivedi void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true)
1429daf82487SKumar Kartikeya Dwivedi {
1430daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
1431daf82487SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
1432daf82487SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_BRANCH,
1433daf82487SKumar Kartikeya Dwivedi 		.branch = {
1434daf82487SKumar Kartikeya Dwivedi 			.cond_true = cond_true,
1435daf82487SKumar Kartikeya Dwivedi 		},
1436daf82487SKumar Kartikeya Dwivedi 	};
1437daf82487SKumar Kartikeya Dwivedi 
1438daf82487SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
1439daf82487SKumar Kartikeya Dwivedi }
1440af4ea6e2SKumar Kartikeya Dwivedi 
diag_snapshot_reg(struct bpf_diag_reg_snapshot * snapshot,const struct bpf_reg_state * reg)1441af4ea6e2SKumar Kartikeya Dwivedi static void diag_snapshot_reg(struct bpf_diag_reg_snapshot *snapshot,
1442af4ea6e2SKumar Kartikeya Dwivedi 			      const struct bpf_reg_state *reg)
1443af4ea6e2SKumar Kartikeya Dwivedi {
1444af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->type = reg->type;
1445af4ea6e2SKumar Kartikeya Dwivedi 	if (type_is_map_ptr(reg->type))
1446af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->map_ptr = reg->map_ptr;
1447af4ea6e2SKumar Kartikeya Dwivedi 	if (base_type(reg->type) == PTR_TO_BTF_ID && reg->btf && reg->btf_id) {
1448af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->btf_id = reg->btf_id;
1449af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->btf = reg->btf;
1450af4ea6e2SKumar Kartikeya Dwivedi 	}
1451af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->var_off = reg->var_off;
1452af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->r64 = reg->r64;
1453af4ea6e2SKumar Kartikeya Dwivedi }
1454af4ea6e2SKumar Kartikeya Dwivedi 
diag_mod_insn_origin(struct bpf_verifier_env * env,u32 insn_idx,const struct bpf_diag_mod_target * target,struct bpf_diag_mod_target * origin)1455af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_insn_origin(struct bpf_verifier_env *env, u32 insn_idx,
1456af4ea6e2SKumar Kartikeya Dwivedi 				 const struct bpf_diag_mod_target *target,
1457af4ea6e2SKumar Kartikeya Dwivedi 				 struct bpf_diag_mod_target *origin)
1458af4ea6e2SKumar Kartikeya Dwivedi {
1459af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_insn *insn = &env->prog->insnsi[insn_idx];
1460af4ea6e2SKumar Kartikeya Dwivedi 	u8 class = BPF_CLASS(insn->code);
1461af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_func_state *state;
1462af4ea6e2SKumar Kartikeya Dwivedi 
1463af4ea6e2SKumar Kartikeya Dwivedi 	if (target->kind == BPF_DIAG_MOD_TARGET_REG && (class == BPF_ALU || class == BPF_ALU64) &&
1464af4ea6e2SKumar Kartikeya Dwivedi 	    BPF_OP(insn->code) == BPF_MOV && BPF_SRC(insn->code) == BPF_X) {
1465af4ea6e2SKumar Kartikeya Dwivedi 		*origin = diag_reg_target(target->frame_id, target->frameno, insn->src_reg);
1466af4ea6e2SKumar Kartikeya Dwivedi 		return true;
1467af4ea6e2SKumar Kartikeya Dwivedi 	}
1468af4ea6e2SKumar Kartikeya Dwivedi 
1469af4ea6e2SKumar Kartikeya Dwivedi 	if ((target->kind != BPF_DIAG_MOD_TARGET_STACK_ARG &&
1470af4ea6e2SKumar Kartikeya Dwivedi 	     target->kind != BPF_DIAG_MOD_TARGET_STACK_SLOT) ||
1471af4ea6e2SKumar Kartikeya Dwivedi 	    class != BPF_STX)
1472af4ea6e2SKumar Kartikeya Dwivedi 		return false;
1473af4ea6e2SKumar Kartikeya Dwivedi 
1474af4ea6e2SKumar Kartikeya Dwivedi 	state = env->cur_state->frame[env->cur_state->curframe];
1475af4ea6e2SKumar Kartikeya Dwivedi 	*origin = diag_reg_target(state->diag_frame_id, state->frameno, insn->src_reg);
1476af4ea6e2SKumar Kartikeya Dwivedi 	return true;
1477af4ea6e2SKumar Kartikeya Dwivedi }
1478af4ea6e2SKumar Kartikeya Dwivedi 
diag_mod_keeps_lineage(struct bpf_verifier_env * env,const struct bpf_diag_history_event * event)1479af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_keeps_lineage(struct bpf_verifier_env *env,
1480af4ea6e2SKumar Kartikeya Dwivedi 				   const struct bpf_diag_history_event *event)
1481af4ea6e2SKumar Kartikeya Dwivedi {
1482af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_insn *insn;
1483af4ea6e2SKumar Kartikeya Dwivedi 	u8 class;
1484af4ea6e2SKumar Kartikeya Dwivedi 
1485af4ea6e2SKumar Kartikeya Dwivedi 	if (event->mod.reason != BPF_DIAG_MOD_WRITE ||
1486af4ea6e2SKumar Kartikeya Dwivedi 	    event->mod.target.kind != BPF_DIAG_MOD_TARGET_REG)
1487af4ea6e2SKumar Kartikeya Dwivedi 		return false;
1488af4ea6e2SKumar Kartikeya Dwivedi 
1489af4ea6e2SKumar Kartikeya Dwivedi 	insn = &env->prog->insnsi[event->insn_idx];
1490af4ea6e2SKumar Kartikeya Dwivedi 	class = BPF_CLASS(insn->code);
1491af4ea6e2SKumar Kartikeya Dwivedi 	if (class != BPF_ALU && class != BPF_ALU64)
1492af4ea6e2SKumar Kartikeya Dwivedi 		return false;
1493af4ea6e2SKumar Kartikeya Dwivedi 
1494af4ea6e2SKumar Kartikeya Dwivedi 	switch (BPF_OP(insn->code)) {
1495af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_ADD:
1496af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_SUB:
1497af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_MUL:
1498af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_OR:
1499af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_AND:
1500af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_LSH:
1501af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_RSH:
1502af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_ARSH:
1503af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_XOR:
1504af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_NEG:
1505af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_END:
1506af4ea6e2SKumar Kartikeya Dwivedi 		return true;
1507af4ea6e2SKumar Kartikeya Dwivedi 	default:
1508af4ea6e2SKumar Kartikeya Dwivedi 		return false;
1509af4ea6e2SKumar Kartikeya Dwivedi 	}
1510af4ea6e2SKumar Kartikeya Dwivedi }
1511af4ea6e2SKumar Kartikeya Dwivedi 
diag_record_mod(struct bpf_verifier_env * env,u32 insn_idx,struct bpf_diag_mod_target target,enum bpf_diag_mod_reason reason,const struct bpf_reg_state * old_reg,const struct bpf_reg_state * new_reg,const struct bpf_diag_mod_target * origin)1512af4ea6e2SKumar Kartikeya Dwivedi static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
1513af4ea6e2SKumar Kartikeya Dwivedi 			    struct bpf_diag_mod_target target,
1514af4ea6e2SKumar Kartikeya Dwivedi 			    enum bpf_diag_mod_reason reason,
1515af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_reg_state *old_reg,
1516af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_reg_state *new_reg,
1517af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_diag_mod_target *origin)
1518af4ea6e2SKumar Kartikeya Dwivedi {
1519af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
1520af4ea6e2SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
1521af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_MOD,
1522af4ea6e2SKumar Kartikeya Dwivedi 		.mod = {
1523af4ea6e2SKumar Kartikeya Dwivedi 			.target = target,
1524af4ea6e2SKumar Kartikeya Dwivedi 			.reason = reason,
1525af4ea6e2SKumar Kartikeya Dwivedi 		},
1526af4ea6e2SKumar Kartikeya Dwivedi 	};
1527af4ea6e2SKumar Kartikeya Dwivedi 
1528af4ea6e2SKumar Kartikeya Dwivedi 	if (old_reg)
1529af4ea6e2SKumar Kartikeya Dwivedi 		diag_snapshot_reg(&event.mod.old, old_reg);
1530af4ea6e2SKumar Kartikeya Dwivedi 	if (new_reg)
1531af4ea6e2SKumar Kartikeya Dwivedi 		diag_snapshot_reg(&event.mod.new, new_reg);
1532af4ea6e2SKumar Kartikeya Dwivedi 	if (origin) {
1533af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin = *origin;
1534af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin_valid = true;
1535af4ea6e2SKumar Kartikeya Dwivedi 	} else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) {
1536af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin_valid = true;
1537af4ea6e2SKumar Kartikeya Dwivedi 	}
1538af4ea6e2SKumar Kartikeya Dwivedi 	if (old_reg && new_reg &&
1539af4ea6e2SKumar Kartikeya Dwivedi 	    (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) &&
1540af4ea6e2SKumar Kartikeya Dwivedi 	    !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) &&
1541af4ea6e2SKumar Kartikeya Dwivedi 	    !event.mod.origin_valid &&
1542af4ea6e2SKumar Kartikeya Dwivedi 	    diag_mod_keeps_lineage(env, &event))
1543af4ea6e2SKumar Kartikeya Dwivedi 		return;
1544af4ea6e2SKumar Kartikeya Dwivedi 
1545af4ea6e2SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
1546af4ea6e2SKumar Kartikeya Dwivedi }
1547af4ea6e2SKumar Kartikeya Dwivedi 
target_to_reg(struct bpf_verifier_env * env,const struct bpf_diag_mod_target * target)1548af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_reg_state *target_to_reg(struct bpf_verifier_env *env,
1549af4ea6e2SKumar Kartikeya Dwivedi 					   const struct bpf_diag_mod_target *target)
1550af4ea6e2SKumar Kartikeya Dwivedi {
1551af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_verifier_state *vstate = env->cur_state;
1552af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_func_state *state;
1553af4ea6e2SKumar Kartikeya Dwivedi 
1554af4ea6e2SKumar Kartikeya Dwivedi 	state = target->frameno <= vstate->curframe ? vstate->frame[target->frameno] : NULL;
1555af4ea6e2SKumar Kartikeya Dwivedi 
1556af4ea6e2SKumar Kartikeya Dwivedi 	if (!state)
1557af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
1558af4ea6e2SKumar Kartikeya Dwivedi 	if (state->diag_frame_id != target->frame_id)
1559af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
1560af4ea6e2SKumar Kartikeya Dwivedi 
1561af4ea6e2SKumar Kartikeya Dwivedi 	switch (target->kind) {
1562af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_REG:
1563af4ea6e2SKumar Kartikeya Dwivedi 		if (target->regno >= MAX_BPF_REG)
1564af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
1565af4ea6e2SKumar Kartikeya Dwivedi 		return &state->regs[target->regno];
1566af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_ARG:
1567af4ea6e2SKumar Kartikeya Dwivedi 		if (target->stack_arg >= state->out_stack_arg_cnt)
1568af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
1569af4ea6e2SKumar Kartikeya Dwivedi 		return &state->stack_arg_regs[target->stack_arg];
1570af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_SLOT:
1571af4ea6e2SKumar Kartikeya Dwivedi 		if (target->spi >= state->allocated_stack / BPF_REG_SIZE)
1572af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
1573af4ea6e2SKumar Kartikeya Dwivedi 		return &state->stack[target->spi].spilled_ptr;
1574af4ea6e2SKumar Kartikeya Dwivedi 	default:
1575af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
1576af4ea6e2SKumar Kartikeya Dwivedi 	}
1577af4ea6e2SKumar Kartikeya Dwivedi }
1578af4ea6e2SKumar Kartikeya Dwivedi 
reg_to_target(struct bpf_verifier_env * env,const struct bpf_reg_state * reg,struct bpf_diag_mod_target * target)1579af4ea6e2SKumar Kartikeya Dwivedi static bool reg_to_target(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
1580af4ea6e2SKumar Kartikeya Dwivedi 			  struct bpf_diag_mod_target *target)
1581af4ea6e2SKumar Kartikeya Dwivedi {
1582af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_verifier_state *vstate = env->cur_state;
1583af4ea6e2SKumar Kartikeya Dwivedi 	unsigned long addr = (unsigned long)reg;
1584af4ea6e2SKumar Kartikeya Dwivedi 	int frame;
1585af4ea6e2SKumar Kartikeya Dwivedi 
1586af4ea6e2SKumar Kartikeya Dwivedi 	for (frame = 0; frame <= vstate->curframe; frame++) {
1587af4ea6e2SKumar Kartikeya Dwivedi 		struct bpf_func_state *state = vstate->frame[frame];
1588af4ea6e2SKumar Kartikeya Dwivedi 		unsigned long start, end;
1589af4ea6e2SKumar Kartikeya Dwivedi 		u32 nslots = state->allocated_stack / BPF_REG_SIZE;
1590af4ea6e2SKumar Kartikeya Dwivedi 		int spi;
1591af4ea6e2SKumar Kartikeya Dwivedi 
1592af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->regs;
1593af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->regs + MAX_BPF_REG);
1594af4ea6e2SKumar Kartikeya Dwivedi 		if (addr >= start && addr < end) {
1595af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_reg_target(state->diag_frame_id, state->frameno,
1596af4ea6e2SKumar Kartikeya Dwivedi 						  reg - state->regs);
1597af4ea6e2SKumar Kartikeya Dwivedi 			return true;
1598af4ea6e2SKumar Kartikeya Dwivedi 		}
1599af4ea6e2SKumar Kartikeya Dwivedi 
1600af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->stack_arg_regs;
1601af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->stack_arg_regs + state->out_stack_arg_cnt);
1602af4ea6e2SKumar Kartikeya Dwivedi 		if (state->out_stack_arg_cnt && addr >= start && addr < end) {
1603af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_stack_arg_target(state->diag_frame_id, state->frameno,
1604af4ea6e2SKumar Kartikeya Dwivedi 							reg - state->stack_arg_regs);
1605af4ea6e2SKumar Kartikeya Dwivedi 			return true;
1606af4ea6e2SKumar Kartikeya Dwivedi 		}
1607af4ea6e2SKumar Kartikeya Dwivedi 
1608af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->stack;
1609af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->stack + nslots);
1610af4ea6e2SKumar Kartikeya Dwivedi 		if (nslots && addr >= start && addr < end) {
1611af4ea6e2SKumar Kartikeya Dwivedi 			spi = ((const char *)reg - (const char *)state->stack) /
1612af4ea6e2SKumar Kartikeya Dwivedi 			      sizeof(*state->stack);
1613af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_stack_slot_target(state->diag_frame_id, state->frameno, spi);
1614af4ea6e2SKumar Kartikeya Dwivedi 			return true;
1615af4ea6e2SKumar Kartikeya Dwivedi 		}
1616af4ea6e2SKumar Kartikeya Dwivedi 	}
1617af4ea6e2SKumar Kartikeya Dwivedi 	return false;
1618af4ea6e2SKumar Kartikeya Dwivedi }
1619af4ea6e2SKumar Kartikeya Dwivedi 
bpf_diag_mod_begin(struct bpf_verifier_env * env,const struct bpf_reg_state * reg,const struct bpf_reg_state * origin,enum bpf_diag_mod_reason reason)1620af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
1621af4ea6e2SKumar Kartikeya Dwivedi 			const struct bpf_reg_state *origin, enum bpf_diag_mod_reason reason)
1622af4ea6e2SKumar Kartikeya Dwivedi {
1623af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
1624af4ea6e2SKumar Kartikeya Dwivedi 
1625af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag)
1626af4ea6e2SKumar Kartikeya Dwivedi 		return;
1627af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.active = reg_to_target(env, reg, &diag->mod.target);
1628af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag->mod.active)
1629af4ea6e2SKumar Kartikeya Dwivedi 		return;
1630af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.target_reg_snapshot = *reg;
1631af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.insn_idx = env->insn_idx;
1632af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.reason = reason;
1633af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.origin_valid = origin && reg_to_target(env, origin, &diag->mod.origin);
1634af4ea6e2SKumar Kartikeya Dwivedi }
1635af4ea6e2SKumar Kartikeya Dwivedi 
bpf_diag_mod_end(struct bpf_verifier_env * env)1636af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_end(struct bpf_verifier_env *env)
1637af4ea6e2SKumar Kartikeya Dwivedi {
1638af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
1639af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_reg_state *new_reg;
1640af4ea6e2SKumar Kartikeya Dwivedi 
1641af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag || !diag->mod.active)
1642af4ea6e2SKumar Kartikeya Dwivedi 		return;
1643af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.active = false;
1644af4ea6e2SKumar Kartikeya Dwivedi 	/*
1645af4ea6e2SKumar Kartikeya Dwivedi 	 * Resolve the target again because the enclosing function state's stack
1646af4ea6e2SKumar Kartikeya Dwivedi 	 * may have been reallocated while the modification was in progress.
1647af4ea6e2SKumar Kartikeya Dwivedi 	 */
1648af4ea6e2SKumar Kartikeya Dwivedi 	new_reg = target_to_reg(env, &diag->mod.target);
1649af4ea6e2SKumar Kartikeya Dwivedi 	if (!new_reg)
1650af4ea6e2SKumar Kartikeya Dwivedi 		return;
1651af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, diag->mod.insn_idx, diag->mod.target, diag->mod.reason,
1652af4ea6e2SKumar Kartikeya Dwivedi 			&diag->mod.target_reg_snapshot, new_reg,
1653af4ea6e2SKumar Kartikeya Dwivedi 			diag->mod.origin_valid ? &diag->mod.origin : NULL);
1654af4ea6e2SKumar Kartikeya Dwivedi }
1655af4ea6e2SKumar Kartikeya Dwivedi 
bpf_diag_record_scrub(struct bpf_verifier_env * env,const struct bpf_reg_state * reg,enum bpf_diag_mod_reason reason)1656af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
1657af4ea6e2SKumar Kartikeya Dwivedi 			   enum bpf_diag_mod_reason reason)
1658af4ea6e2SKumar Kartikeya Dwivedi {
1659af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
1660af4ea6e2SKumar Kartikeya Dwivedi 
1661af4ea6e2SKumar Kartikeya Dwivedi 	if (!env->diag || reg->type == NOT_INIT || !reg_to_target(env, reg, &target))
1662af4ea6e2SKumar Kartikeya Dwivedi 		return;
1663af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, env->insn_idx, target, reason, reg, NULL, NULL);
1664af4ea6e2SKumar Kartikeya Dwivedi }
1665af4ea6e2SKumar Kartikeya Dwivedi 
bpf_diag_record_scrub_stack(struct bpf_verifier_env * env,const struct bpf_func_state * state,s16 min_off,s16 max_off,enum bpf_diag_mod_reason reason)1666af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub_stack(struct bpf_verifier_env *env,
1667af4ea6e2SKumar Kartikeya Dwivedi 				 const struct bpf_func_state *state, s16 min_off, s16 max_off,
1668af4ea6e2SKumar Kartikeya Dwivedi 				 enum bpf_diag_mod_reason reason)
1669af4ea6e2SKumar Kartikeya Dwivedi {
1670af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, env->insn_idx,
1671af4ea6e2SKumar Kartikeya Dwivedi 			diag_stack_range_target(state->diag_frame_id, state->frameno, min_off, max_off),
1672af4ea6e2SKumar Kartikeya Dwivedi 			reason, NULL, NULL, NULL);
1673af4ea6e2SKumar Kartikeya Dwivedi }
16749ecd7030SKumar Kartikeya Dwivedi 
diag_record_ref(struct bpf_verifier_env * env,u32 insn_idx,u8 kind,u32 ref_id)16759ecd7030SKumar Kartikeya Dwivedi static void diag_record_ref(struct bpf_verifier_env *env, u32 insn_idx, u8 kind, u32 ref_id)
16769ecd7030SKumar Kartikeya Dwivedi {
16779ecd7030SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
16789ecd7030SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
16799ecd7030SKumar Kartikeya Dwivedi 		.kind = kind,
16809ecd7030SKumar Kartikeya Dwivedi 		.ref = {
16819ecd7030SKumar Kartikeya Dwivedi 			.ref_id = ref_id,
16829ecd7030SKumar Kartikeya Dwivedi 		},
16839ecd7030SKumar Kartikeya Dwivedi 	};
16849ecd7030SKumar Kartikeya Dwivedi 
16859ecd7030SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
16869ecd7030SKumar Kartikeya Dwivedi }
16879ecd7030SKumar Kartikeya Dwivedi 
bpf_diag_record_ref_acquire(struct bpf_verifier_env * env,u32 insn_idx,u32 ref_id)16889ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
16899ecd7030SKumar Kartikeya Dwivedi {
16909ecd7030SKumar Kartikeya Dwivedi 	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_ACQUIRE, ref_id);
16919ecd7030SKumar Kartikeya Dwivedi }
16929ecd7030SKumar Kartikeya Dwivedi 
bpf_diag_record_ref_release(struct bpf_verifier_env * env,u32 insn_idx,u32 ref_id)16939ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
16949ecd7030SKumar Kartikeya Dwivedi {
16959ecd7030SKumar Kartikeya Dwivedi 	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id);
16969ecd7030SKumar Kartikeya Dwivedi }
1697956a66e5SKumar Kartikeya Dwivedi 
bpf_diag_record_context(struct bpf_verifier_env * env,u32 insn_idx,enum bpf_diag_context_kind ctx_kind,bool enter,u32 depth)1698956a66e5SKumar Kartikeya Dwivedi void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx,
1699956a66e5SKumar Kartikeya Dwivedi 			     enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth)
1700956a66e5SKumar Kartikeya Dwivedi {
1701956a66e5SKumar Kartikeya Dwivedi 	/*
1702956a66e5SKumar Kartikeya Dwivedi 	 * Keep leave events so context rendering can stop at a depth-zero exit
1703956a66e5SKumar Kartikeya Dwivedi 	 * and show nested-region depth accurately for the active path.
1704956a66e5SKumar Kartikeya Dwivedi 	 */
1705956a66e5SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
1706956a66e5SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
1707956a66e5SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_CONTEXT,
1708956a66e5SKumar Kartikeya Dwivedi 		.ctx = {
1709956a66e5SKumar Kartikeya Dwivedi 			.kind = ctx_kind,
1710956a66e5SKumar Kartikeya Dwivedi 			.enter = enter,
1711956a66e5SKumar Kartikeya Dwivedi 			.depth = depth,
1712956a66e5SKumar Kartikeya Dwivedi 		},
1713956a66e5SKumar Kartikeya Dwivedi 	};
1714956a66e5SKumar Kartikeya Dwivedi 
1715956a66e5SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
1716956a66e5SKumar Kartikeya Dwivedi }
1717d63284e6SKumar Kartikeya Dwivedi 
diag_history_context_start_idx(const struct bpf_diag_log * log,const struct bpf_diag_history_opts * opts)1718d63284e6SKumar Kartikeya Dwivedi static int diag_history_context_start_idx(const struct bpf_diag_log *log,
1719d63284e6SKumar Kartikeya Dwivedi 					  const struct bpf_diag_history_opts *opts)
1720d63284e6SKumar Kartikeya Dwivedi {
1721d63284e6SKumar Kartikeya Dwivedi 	int i;
1722d63284e6SKumar Kartikeya Dwivedi 
1723d63284e6SKumar Kartikeya Dwivedi 	if (!opts->ctx_depth)
1724d63284e6SKumar Kartikeya Dwivedi 		return 0;
1725d63284e6SKumar Kartikeya Dwivedi 
1726d63284e6SKumar Kartikeya Dwivedi 	/* Find the most recent outermost entry, or a depth-zero exit. */
1727d63284e6SKumar Kartikeya Dwivedi 	for (i = log->cnt; i > 0; i--) {
1728d63284e6SKumar Kartikeya Dwivedi 		const struct bpf_diag_history_event *event;
1729d63284e6SKumar Kartikeya Dwivedi 
1730d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i - 1)];
1731d63284e6SKumar Kartikeya Dwivedi 
1732d63284e6SKumar Kartikeya Dwivedi 		if (event->kind != BPF_DIAG_HISTORY_CONTEXT || event->ctx.kind != opts->ctx_kind)
1733d63284e6SKumar Kartikeya Dwivedi 			continue;
1734d63284e6SKumar Kartikeya Dwivedi 
1735d63284e6SKumar Kartikeya Dwivedi 		if (event->ctx.enter && event->ctx.depth == 1)
1736d63284e6SKumar Kartikeya Dwivedi 			return i - 1;
1737d63284e6SKumar Kartikeya Dwivedi 		if (!event->ctx.enter && event->ctx.depth == 0)
1738d63284e6SKumar Kartikeya Dwivedi 			return 0;
1739d63284e6SKumar Kartikeya Dwivedi 	}
1740d63284e6SKumar Kartikeya Dwivedi 
1741d63284e6SKumar Kartikeya Dwivedi 	return 0;
1742d63284e6SKumar Kartikeya Dwivedi }
1743d63284e6SKumar Kartikeya Dwivedi 
1744d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_filter {
1745d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_history_opts *opts;
1746d63284e6SKumar Kartikeya Dwivedi 	u32 lineage_start;
1747d63284e6SKumar Kartikeya Dwivedi 	bool lineage_valid;
1748d63284e6SKumar Kartikeya Dwivedi };
1749d63284e6SKumar Kartikeya Dwivedi 
diag_target_matches(const struct bpf_diag_mod_target * event_target,const struct bpf_diag_mod_target * target)1750d63284e6SKumar Kartikeya Dwivedi static bool diag_target_matches(const struct bpf_diag_mod_target *event_target,
1751d63284e6SKumar Kartikeya Dwivedi 				const struct bpf_diag_mod_target *target)
1752d63284e6SKumar Kartikeya Dwivedi {
1753d63284e6SKumar Kartikeya Dwivedi 	int slot_off;
1754d63284e6SKumar Kartikeya Dwivedi 
1755d63284e6SKumar Kartikeya Dwivedi 	if (event_target->frame_id != target->frame_id || event_target->frameno != target->frameno)
1756d63284e6SKumar Kartikeya Dwivedi 		return false;
1757d63284e6SKumar Kartikeya Dwivedi 
1758d63284e6SKumar Kartikeya Dwivedi 	if (event_target->kind == BPF_DIAG_MOD_TARGET_STACK_RANGE &&
1759d63284e6SKumar Kartikeya Dwivedi 	    target->kind == BPF_DIAG_MOD_TARGET_STACK_SLOT) {
1760d63284e6SKumar Kartikeya Dwivedi 		slot_off = -(target->spi + 1) * BPF_REG_SIZE;
1761d63284e6SKumar Kartikeya Dwivedi 		return event_target->range.min_off < slot_off + BPF_REG_SIZE &&
1762d63284e6SKumar Kartikeya Dwivedi 		       event_target->range.max_off > slot_off;
1763d63284e6SKumar Kartikeya Dwivedi 	}
1764d63284e6SKumar Kartikeya Dwivedi 
1765d63284e6SKumar Kartikeya Dwivedi 	if (event_target->kind != target->kind)
1766d63284e6SKumar Kartikeya Dwivedi 		return false;
1767d63284e6SKumar Kartikeya Dwivedi 
1768d63284e6SKumar Kartikeya Dwivedi 	switch (target->kind) {
1769d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_REG:
1770d63284e6SKumar Kartikeya Dwivedi 		return event_target->regno == target->regno;
1771d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_ARG:
1772d63284e6SKumar Kartikeya Dwivedi 		return event_target->stack_arg == target->stack_arg;
1773d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_SLOT:
1774d63284e6SKumar Kartikeya Dwivedi 		return event_target->spi == target->spi;
1775d63284e6SKumar Kartikeya Dwivedi 	default:
1776d63284e6SKumar Kartikeya Dwivedi 		return false;
1777d63284e6SKumar Kartikeya Dwivedi 	}
1778d63284e6SKumar Kartikeya Dwivedi }
1779d63284e6SKumar Kartikeya Dwivedi 
diag_build_lineage(struct bpf_verifier_env * env,struct bpf_diag_log * log,struct bpf_diag_history_filter * filter)1780d63284e6SKumar Kartikeya Dwivedi static void diag_build_lineage(struct bpf_verifier_env *env, struct bpf_diag_log *log,
1781d63284e6SKumar Kartikeya Dwivedi 			       struct bpf_diag_history_filter *filter)
1782d63284e6SKumar Kartikeya Dwivedi {
1783d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_history_opts *opts = filter->opts;
1784d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
1785d63284e6SKumar Kartikeya Dwivedi 	int i;
1786d63284e6SKumar Kartikeya Dwivedi 
1787d63284e6SKumar Kartikeya Dwivedi 	for (i = 0; i < log->cnt; i++)
1788d63284e6SKumar Kartikeya Dwivedi 		log->events[log_pos(log, i)].in_lineage = false;
1789d63284e6SKumar Kartikeya Dwivedi 
1790d63284e6SKumar Kartikeya Dwivedi 	if (opts->scope == BPF_DIAG_HISTORY_SCOPE_REG)
1791d63284e6SKumar Kartikeya Dwivedi 		target = diag_reg_target(opts->frame_id, opts->frameno, opts->regno);
1792d63284e6SKumar Kartikeya Dwivedi 	else if (opts->scope == BPF_DIAG_HISTORY_SCOPE_STACK_ARG)
1793d63284e6SKumar Kartikeya Dwivedi 		target = diag_stack_arg_target(opts->frame_id, opts->frameno,
1794d63284e6SKumar Kartikeya Dwivedi 					       opts->stack_arg_slot);
1795d63284e6SKumar Kartikeya Dwivedi 	else
1796d63284e6SKumar Kartikeya Dwivedi 		return;
1797d63284e6SKumar Kartikeya Dwivedi 
1798d63284e6SKumar Kartikeya Dwivedi 	/*
1799d63284e6SKumar Kartikeya Dwivedi 	 * Find the nearest mutation of the active target. A fill or spill changes
1800d63284e6SKumar Kartikeya Dwivedi 	 * the target to its origin, so the same walk follows register/stack
1801d63284e6SKumar Kartikeya Dwivedi 	 * lineage recursively until it reaches the write that created the value.
1802d63284e6SKumar Kartikeya Dwivedi 	 */
1803d63284e6SKumar Kartikeya Dwivedi 	for (i = log->cnt; i > 0; i--) {
1804d63284e6SKumar Kartikeya Dwivedi 		struct bpf_diag_history_event *event;
1805d63284e6SKumar Kartikeya Dwivedi 
1806d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i - 1)];
1807d63284e6SKumar Kartikeya Dwivedi 		if (event->kind != BPF_DIAG_HISTORY_MOD ||
1808d63284e6SKumar Kartikeya Dwivedi 		    !diag_target_matches(&event->mod.target, &target))
1809d63284e6SKumar Kartikeya Dwivedi 			continue;
1810d63284e6SKumar Kartikeya Dwivedi 
1811d63284e6SKumar Kartikeya Dwivedi 		event->in_lineage = true;
1812d63284e6SKumar Kartikeya Dwivedi 		filter->lineage_start = i - 1;
1813d63284e6SKumar Kartikeya Dwivedi 		filter->lineage_valid = true;
1814d63284e6SKumar Kartikeya Dwivedi 
1815d63284e6SKumar Kartikeya Dwivedi 		if (event->mod.origin_valid) {
1816d63284e6SKumar Kartikeya Dwivedi 			target = event->mod.origin;
1817d63284e6SKumar Kartikeya Dwivedi 			continue;
1818d63284e6SKumar Kartikeya Dwivedi 		}
1819d63284e6SKumar Kartikeya Dwivedi 		if (event->mod.reason != BPF_DIAG_MOD_WRITE &&
1820d63284e6SKumar Kartikeya Dwivedi 		    event->mod.reason != BPF_DIAG_MOD_SPILL)
1821d63284e6SKumar Kartikeya Dwivedi 			continue;
1822d63284e6SKumar Kartikeya Dwivedi 		if (diag_mod_keeps_lineage(env, event))
1823d63284e6SKumar Kartikeya Dwivedi 			continue;
1824d63284e6SKumar Kartikeya Dwivedi 		break;
1825d63284e6SKumar Kartikeya Dwivedi 	}
1826d63284e6SKumar Kartikeya Dwivedi }
1827d63284e6SKumar Kartikeya Dwivedi 
diag_history_start_idx(const struct bpf_diag_log * log,const struct bpf_diag_history_filter * filter)1828d63284e6SKumar Kartikeya Dwivedi static int diag_history_start_idx(const struct bpf_diag_log *log,
1829d63284e6SKumar Kartikeya Dwivedi 				  const struct bpf_diag_history_filter *filter)
1830d63284e6SKumar Kartikeya Dwivedi {
1831d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_history_opts *opts = filter->opts;
1832d63284e6SKumar Kartikeya Dwivedi 	int i;
1833d63284e6SKumar Kartikeya Dwivedi 
1834d63284e6SKumar Kartikeya Dwivedi 	if (opts->scope == BPF_DIAG_HISTORY_SCOPE_CONTEXT)
1835d63284e6SKumar Kartikeya Dwivedi 		return diag_history_context_start_idx(log, opts);
1836d63284e6SKumar Kartikeya Dwivedi 	if (filter->lineage_valid)
1837d63284e6SKumar Kartikeya Dwivedi 		return filter->lineage_start;
1838d63284e6SKumar Kartikeya Dwivedi 	if (opts->scope != BPF_DIAG_HISTORY_SCOPE_REF)
1839d63284e6SKumar Kartikeya Dwivedi 		return 0;
1840d63284e6SKumar Kartikeya Dwivedi 
1841d63284e6SKumar Kartikeya Dwivedi 	for (i = log->cnt; i > 0; i--) {
1842d63284e6SKumar Kartikeya Dwivedi 		const struct bpf_diag_history_event *event;
1843d63284e6SKumar Kartikeya Dwivedi 
1844d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i - 1)];
1845d63284e6SKumar Kartikeya Dwivedi 		if (event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE &&
1846d63284e6SKumar Kartikeya Dwivedi 		    event->ref.ref_id == opts->ref_id)
1847d63284e6SKumar Kartikeya Dwivedi 			return i - 1;
1848d63284e6SKumar Kartikeya Dwivedi 	}
1849d63284e6SKumar Kartikeya Dwivedi 
1850d63284e6SKumar Kartikeya Dwivedi 	return 0;
1851d63284e6SKumar Kartikeya Dwivedi }
1852d63284e6SKumar Kartikeya Dwivedi 
diag_history_event_visible(const struct bpf_diag_history_event * event,const struct bpf_diag_history_filter * filter)1853d63284e6SKumar Kartikeya Dwivedi static bool diag_history_event_visible(const struct bpf_diag_history_event *event,
1854d63284e6SKumar Kartikeya Dwivedi 				       const struct bpf_diag_history_filter *filter)
1855d63284e6SKumar Kartikeya Dwivedi {
1856d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_history_opts *opts = filter->opts;
1857d63284e6SKumar Kartikeya Dwivedi 
1858d63284e6SKumar Kartikeya Dwivedi 	switch (event->kind) {
1859d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_HISTORY_BRANCH:
1860d63284e6SKumar Kartikeya Dwivedi 		return true;
1861d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_HISTORY_MOD:
1862d63284e6SKumar Kartikeya Dwivedi 		return filter->lineage_valid && event->in_lineage;
1863d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_HISTORY_REF_ACQUIRE:
1864d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_HISTORY_REF_RELEASE:
1865d63284e6SKumar Kartikeya Dwivedi 		return opts->scope == BPF_DIAG_HISTORY_SCOPE_REF &&
1866d63284e6SKumar Kartikeya Dwivedi 		       event->ref.ref_id == opts->ref_id;
1867d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_HISTORY_CONTEXT:
1868d63284e6SKumar Kartikeya Dwivedi 		return opts->scope == BPF_DIAG_HISTORY_SCOPE_CONTEXT &&
1869d63284e6SKumar Kartikeya Dwivedi 		       event->ctx.kind == opts->ctx_kind;
1870d63284e6SKumar Kartikeya Dwivedi 	default:
1871d63284e6SKumar Kartikeya Dwivedi 		return false;
1872d63284e6SKumar Kartikeya Dwivedi 	}
1873d63284e6SKumar Kartikeya Dwivedi }
1874d63284e6SKumar Kartikeya Dwivedi 
diag_s64_bound_name(s64 value)1875d63284e6SKumar Kartikeya Dwivedi static const char *diag_s64_bound_name(s64 value)
1876d63284e6SKumar Kartikeya Dwivedi {
1877d63284e6SKumar Kartikeya Dwivedi 	if (value == S64_MIN)
1878d63284e6SKumar Kartikeya Dwivedi 		return "S64_MIN";
1879d63284e6SKumar Kartikeya Dwivedi 	if (value == S64_MAX)
1880d63284e6SKumar Kartikeya Dwivedi 		return "S64_MAX";
1881d63284e6SKumar Kartikeya Dwivedi 	return NULL;
1882d63284e6SKumar Kartikeya Dwivedi }
1883d63284e6SKumar Kartikeya Dwivedi 
diag_u64_bound_name(u64 value)1884d63284e6SKumar Kartikeya Dwivedi static const char *diag_u64_bound_name(u64 value)
1885d63284e6SKumar Kartikeya Dwivedi {
1886d63284e6SKumar Kartikeya Dwivedi 	if (value == U64_MAX)
1887d63284e6SKumar Kartikeya Dwivedi 		return "U64_MAX";
1888d63284e6SKumar Kartikeya Dwivedi 	return NULL;
1889d63284e6SKumar Kartikeya Dwivedi }
1890d63284e6SKumar Kartikeya Dwivedi 
diag_s64_str(struct bpf_verifier_env * env,s64 value)1891d63284e6SKumar Kartikeya Dwivedi static const char *diag_s64_str(struct bpf_verifier_env *env, s64 value)
1892d63284e6SKumar Kartikeya Dwivedi {
1893d63284e6SKumar Kartikeya Dwivedi 	return diag_s64_bound_name(value) ?: bpf_diag_fmt(env, "%lld", value);
1894d63284e6SKumar Kartikeya Dwivedi }
1895d63284e6SKumar Kartikeya Dwivedi 
diag_u64_str(struct bpf_verifier_env * env,u64 value)1896d63284e6SKumar Kartikeya Dwivedi static const char *diag_u64_str(struct bpf_verifier_env *env, u64 value)
1897d63284e6SKumar Kartikeya Dwivedi {
1898d63284e6SKumar Kartikeya Dwivedi 	return diag_u64_bound_name(value) ?: bpf_diag_fmt(env, "%llu", value);
1899d63284e6SKumar Kartikeya Dwivedi }
1900d63284e6SKumar Kartikeya Dwivedi 
diag_cnum64_unknown(struct cnum64 range)1901d63284e6SKumar Kartikeya Dwivedi static bool diag_cnum64_unknown(struct cnum64 range)
1902d63284e6SKumar Kartikeya Dwivedi {
1903d63284e6SKumar Kartikeya Dwivedi 	return cnum64_smin(range) == S64_MIN && cnum64_smax(range) == S64_MAX &&
1904d63284e6SKumar Kartikeya Dwivedi 	       cnum64_umin(range) == 0 && cnum64_umax(range) == U64_MAX;
1905d63284e6SKumar Kartikeya Dwivedi }
1906d63284e6SKumar Kartikeya Dwivedi 
diag_snapshot_unknown(const struct bpf_diag_reg_snapshot * snapshot)1907d63284e6SKumar Kartikeya Dwivedi static bool diag_snapshot_unknown(const struct bpf_diag_reg_snapshot *snapshot)
1908d63284e6SKumar Kartikeya Dwivedi {
1909d63284e6SKumar Kartikeya Dwivedi 	return tnum_is_unknown(snapshot->var_off) && diag_cnum64_unknown(snapshot->r64);
1910d63284e6SKumar Kartikeya Dwivedi }
1911d63284e6SKumar Kartikeya Dwivedi 
diag_scalar_range(struct bpf_verifier_env * env,struct cnum64 range)1912d63284e6SKumar Kartikeya Dwivedi static const char *diag_scalar_range(struct bpf_verifier_env *env, struct cnum64 range)
1913d63284e6SKumar Kartikeya Dwivedi {
1914d63284e6SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env, "signed range [%s, %s], unsigned range [%s, %s]",
1915d63284e6SKumar Kartikeya Dwivedi 			    diag_s64_str(env, cnum64_smin(range)),
1916d63284e6SKumar Kartikeya Dwivedi 			    diag_s64_str(env, cnum64_smax(range)),
1917d63284e6SKumar Kartikeya Dwivedi 			    diag_u64_str(env, cnum64_umin(range)),
1918d63284e6SKumar Kartikeya Dwivedi 			    diag_u64_str(env, cnum64_umax(range)));
1919d63284e6SKumar Kartikeya Dwivedi }
1920d63284e6SKumar Kartikeya Dwivedi 
bpf_diag_fmt_s64_sum(struct bpf_verifier_env * env,s64 value,int addend)19212bdc90f5SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_s64_sum(struct bpf_verifier_env *env, s64 value, int addend)
19222bdc90f5SKumar Kartikeya Dwivedi {
19232bdc90f5SKumar Kartikeya Dwivedi 	s64 sum;
19242bdc90f5SKumar Kartikeya Dwivedi 
19252bdc90f5SKumar Kartikeya Dwivedi 	if (check_add_overflow(value, (s64)addend, &sum))
19262bdc90f5SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "%lld plus %d (%s)", value, addend,
19272bdc90f5SKumar Kartikeya Dwivedi 				    addend < 0 ? "below S64_MIN" : "above S64_MAX");
19282bdc90f5SKumar Kartikeya Dwivedi 
19292bdc90f5SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env, "%lld", sum);
19302bdc90f5SKumar Kartikeya Dwivedi }
19312bdc90f5SKumar Kartikeya Dwivedi 
diag_access_offset(struct bpf_verifier_env * env,int off,const struct bpf_reg_state * reg)19322bdc90f5SKumar Kartikeya Dwivedi static const char *diag_access_offset(struct bpf_verifier_env *env, int off,
19332bdc90f5SKumar Kartikeya Dwivedi 				      const struct bpf_reg_state *reg)
19342bdc90f5SKumar Kartikeya Dwivedi {
19352bdc90f5SKumar Kartikeya Dwivedi 	if (tnum_is_const(reg->var_off))
19362bdc90f5SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "constant %s",
19372bdc90f5SKumar Kartikeya Dwivedi 				    bpf_diag_fmt_s64_sum(env, (s64)reg->var_off.value, off));
19382bdc90f5SKumar Kartikeya Dwivedi 
19392bdc90f5SKumar Kartikeya Dwivedi 	if (tnum_is_unknown(reg->var_off) && diag_cnum64_unknown(reg->r64))
19402bdc90f5SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "unbounded");
19412bdc90f5SKumar Kartikeya Dwivedi 
19422bdc90f5SKumar Kartikeya Dwivedi 	if (off)
19432bdc90f5SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env,
19442bdc90f5SKumar Kartikeya Dwivedi 			"variable: known bits %#llx, unknown mask %#llx, plus fixed offset %d; %s",
19452bdc90f5SKumar Kartikeya Dwivedi 			(u64)reg->var_off.value, reg->var_off.mask, off,
19462bdc90f5SKumar Kartikeya Dwivedi 			diag_scalar_range(env, reg->r64));
19472bdc90f5SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env, "variable: known bits %#llx, unknown mask %#llx; %s",
19482bdc90f5SKumar Kartikeya Dwivedi 			    (u64)reg->var_off.value, reg->var_off.mask,
19492bdc90f5SKumar Kartikeya Dwivedi 			    diag_scalar_range(env, reg->r64));
19502bdc90f5SKumar Kartikeya Dwivedi }
19512bdc90f5SKumar Kartikeya Dwivedi 
bpf_diag_mem_bounds(struct bpf_verifier_env * env,u32 insn_idx,int regno,const char * reg_name,const char * type_name,const char * proof,int off,int size,u32 mem_size,const struct bpf_reg_state * reg)19522bdc90f5SKumar Kartikeya Dwivedi void bpf_diag_mem_bounds(struct bpf_verifier_env *env, u32 insn_idx, int regno,
19532bdc90f5SKumar Kartikeya Dwivedi 			 const char *reg_name, const char *type_name, const char *proof,
19542bdc90f5SKumar Kartikeya Dwivedi 			 int off, int size, u32 mem_size, const struct bpf_reg_state *reg)
19552bdc90f5SKumar Kartikeya Dwivedi {
19562bdc90f5SKumar Kartikeya Dwivedi 	const struct bpf_func_state *frame = diag_current_frame(env);
19572bdc90f5SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
19582bdc90f5SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_REG,
19592bdc90f5SKumar Kartikeya Dwivedi 		.frame_id = frame->diag_frame_id,
19602bdc90f5SKumar Kartikeya Dwivedi 		.frameno = frame->frameno,
19612bdc90f5SKumar Kartikeya Dwivedi 		.regno = regno,
19622bdc90f5SKumar Kartikeya Dwivedi 	};
19632bdc90f5SKumar Kartikeya Dwivedi 	const char *offset_desc;
19642bdc90f5SKumar Kartikeya Dwivedi 
19652bdc90f5SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
19662bdc90f5SKumar Kartikeya Dwivedi 		return;
19672bdc90f5SKumar Kartikeya Dwivedi 
19682bdc90f5SKumar Kartikeya Dwivedi 	offset_desc = diag_access_offset(env, off, reg);
19692bdc90f5SKumar Kartikeya Dwivedi 
19702bdc90f5SKumar Kartikeya Dwivedi 	bpf_diag_header(env, MEMORY_SAFETY, "access outside bounds");
19712bdc90f5SKumar Kartikeya Dwivedi 	diag_reason(
19722bdc90f5SKumar Kartikeya Dwivedi 		env, "The verifier cannot prove offset + access_size <= object_size. Here, %s. %s is %s; offset is %s; access_size is %d; object_size is %u.",
19732bdc90f5SKumar Kartikeya Dwivedi 		proof, reg_name, type_name, offset_desc, size, mem_size);
19742bdc90f5SKumar Kartikeya Dwivedi 
19752bdc90f5SKumar Kartikeya Dwivedi 	diag_section(env, "At");
19762bdc90f5SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "access may be outside object bounds");
19772bdc90f5SKumar Kartikeya Dwivedi 
19782bdc90f5SKumar Kartikeya Dwivedi 	if (regno >= 0)
19792bdc90f5SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
19802bdc90f5SKumar Kartikeya Dwivedi 
19812bdc90f5SKumar Kartikeya Dwivedi 	diag_suggestion(
19822bdc90f5SKumar Kartikeya Dwivedi 		env, "Add or adjust a bounds check that proves offset + access_size stays within the object.");
19832bdc90f5SKumar Kartikeya Dwivedi }
19842bdc90f5SKumar Kartikeya Dwivedi 
diag_lock_name(const struct bpf_reference_state * lock)19855d576462SKumar Kartikeya Dwivedi static const char *diag_lock_name(const struct bpf_reference_state *lock)
19865d576462SKumar Kartikeya Dwivedi {
19875d576462SKumar Kartikeya Dwivedi 	switch (lock->type) {
19885d576462SKumar Kartikeya Dwivedi 	case REF_TYPE_LOCK:
19895d576462SKumar Kartikeya Dwivedi 		return "bpf_spin_lock";
19905d576462SKumar Kartikeya Dwivedi 	case REF_TYPE_RES_LOCK:
19915d576462SKumar Kartikeya Dwivedi 		return "resource spin lock";
19925d576462SKumar Kartikeya Dwivedi 	case REF_TYPE_RES_LOCK_IRQ:
19935d576462SKumar Kartikeya Dwivedi 		return "IRQ-saving resource spin lock";
19945d576462SKumar Kartikeya Dwivedi 	default:
19955d576462SKumar Kartikeya Dwivedi 		return "lock";
19965d576462SKumar Kartikeya Dwivedi 	}
19975d576462SKumar Kartikeya Dwivedi }
19985d576462SKumar Kartikeya Dwivedi 
diag_res_report(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * reason)19995d576462SKumar Kartikeya Dwivedi static void diag_res_report(struct bpf_verifier_env *env, u32 insn_idx, const char *problem,
20005d576462SKumar Kartikeya Dwivedi 			    const char *reason)
20015d576462SKumar Kartikeya Dwivedi {
20025d576462SKumar Kartikeya Dwivedi 	bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, problem);
20035d576462SKumar Kartikeya Dwivedi 	diag_reason(env, "%s", reason);
20045d576462SKumar Kartikeya Dwivedi 
20055d576462SKumar Kartikeya Dwivedi 	diag_section(env, "At");
20065d576462SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s", problem);
20075d576462SKumar Kartikeya Dwivedi }
20085d576462SKumar Kartikeya Dwivedi 
bpf_diag_res(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * reason,const char * suggestion)20095d576462SKumar Kartikeya Dwivedi void bpf_diag_res(struct bpf_verifier_env *env, u32 insn_idx, const char *problem,
20105d576462SKumar Kartikeya Dwivedi 		  const char *reason, const char *suggestion)
20115d576462SKumar Kartikeya Dwivedi {
20125d576462SKumar Kartikeya Dwivedi 	diag_res_report(env, insn_idx, problem, reason);
20135d576462SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
20145d576462SKumar Kartikeya Dwivedi }
20155d576462SKumar Kartikeya Dwivedi 
bpf_diag_lock(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * reason,const char * suggestion,const struct bpf_reference_state * active_lock)20165d576462SKumar Kartikeya Dwivedi void bpf_diag_lock(struct bpf_verifier_env *env, u32 insn_idx, const char *problem,
20175d576462SKumar Kartikeya Dwivedi 		   const char *reason, const char *suggestion,
20185d576462SKumar Kartikeya Dwivedi 		   const struct bpf_reference_state *active_lock)
20195d576462SKumar Kartikeya Dwivedi {
20205d576462SKumar Kartikeya Dwivedi 	diag_res_report(env, insn_idx, problem, reason);
20215d576462SKumar Kartikeya Dwivedi 
20225d576462SKumar Kartikeya Dwivedi 	if (active_lock) {
20235d576462SKumar Kartikeya Dwivedi 		diag_section(env, "Active lock");
20245d576462SKumar Kartikeya Dwivedi 		bpf_diag_source(env, active_lock->insn_idx, "acquired",
20255d576462SKumar Kartikeya Dwivedi 				"active %s has verifier identity %d",
20265d576462SKumar Kartikeya Dwivedi 				diag_lock_name(active_lock), active_lock->id);
20275d576462SKumar Kartikeya Dwivedi 	}
20285d576462SKumar Kartikeya Dwivedi 
20295d576462SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
20305d576462SKumar Kartikeya Dwivedi }
20315d576462SKumar Kartikeya Dwivedi 
bpf_diag_irq(struct bpf_verifier_env * env,u32 insn_idx,const char * problem,const char * reason,const char * suggestion,u32 depth)20325d576462SKumar Kartikeya Dwivedi void bpf_diag_irq(struct bpf_verifier_env *env, u32 insn_idx, const char *problem,
20335d576462SKumar Kartikeya Dwivedi 		  const char *reason, const char *suggestion, u32 depth)
20345d576462SKumar Kartikeya Dwivedi {
20355d576462SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
20365d576462SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT,
20375d576462SKumar Kartikeya Dwivedi 		.ctx_kind = BPF_DIAG_CONTEXT_IRQ,
20385d576462SKumar Kartikeya Dwivedi 		.ctx_depth = depth,
20395d576462SKumar Kartikeya Dwivedi 	};
20405d576462SKumar Kartikeya Dwivedi 
20415d576462SKumar Kartikeya Dwivedi 	bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, problem);
20425d576462SKumar Kartikeya Dwivedi 	diag_reason(env, "%s", reason);
20435d576462SKumar Kartikeya Dwivedi 
20445d576462SKumar Kartikeya Dwivedi 	diag_section(env, "At");
20455d576462SKumar Kartikeya Dwivedi 	bpf_diag_source(env, insn_idx, "error", "%s", problem);
20465d576462SKumar Kartikeya Dwivedi 
20475d576462SKumar Kartikeya Dwivedi 	if (depth)
20485d576462SKumar Kartikeya Dwivedi 		diag_print_history(env, &opts);
20495d576462SKumar Kartikeya Dwivedi 
20505d576462SKumar Kartikeya Dwivedi 	diag_suggestion(env, "%s", suggestion);
20515d576462SKumar Kartikeya Dwivedi }
20525d576462SKumar Kartikeya Dwivedi 
bpf_diag_leak(struct bpf_verifier_env * env,u32 ref_id,u32 alloc_insn,u32 fail_insn)20535d576462SKumar Kartikeya Dwivedi void bpf_diag_leak(struct bpf_verifier_env *env, u32 ref_id, u32 alloc_insn, u32 fail_insn)
20545d576462SKumar Kartikeya Dwivedi {
20555d576462SKumar Kartikeya Dwivedi 	struct bpf_diag_history_opts opts = {
20565d576462SKumar Kartikeya Dwivedi 		.scope = BPF_DIAG_HISTORY_SCOPE_REF,
20575d576462SKumar Kartikeya Dwivedi 		.ref_id = ref_id,
20585d576462SKumar Kartikeya Dwivedi 	};
20595d576462SKumar Kartikeya Dwivedi 
20605d576462SKumar Kartikeya Dwivedi 	bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, "unreleased resource");
20615d576462SKumar Kartikeya Dwivedi 	diag_reason(
20625d576462SKumar Kartikeya Dwivedi 		env, "Owned resource (id=%u) was acquired at instruction %u and still needs to be released before this exit path.",
20635d576462SKumar Kartikeya Dwivedi 		ref_id, alloc_insn);
20645d576462SKumar Kartikeya Dwivedi 
20655d576462SKumar Kartikeya Dwivedi 	diag_section(env, "At");
20665d576462SKumar Kartikeya Dwivedi 	bpf_diag_source(env, fail_insn, "error",
20675d576462SKumar Kartikeya Dwivedi 			"owned resource (id=%u) still needs release", ref_id);
20685d576462SKumar Kartikeya Dwivedi 
20695d576462SKumar Kartikeya Dwivedi 	diag_print_history(env, &opts);
20705d576462SKumar Kartikeya Dwivedi 
20715d576462SKumar Kartikeya Dwivedi 	diag_suggestion(
20725d576462SKumar Kartikeya Dwivedi 		env, "Release or transfer ownership of the acquired resource on every path before the program exits.");
20735d576462SKumar Kartikeya Dwivedi }
20745d576462SKumar Kartikeya Dwivedi 
diag_var_offset(struct bpf_verifier_env * env,const struct bpf_diag_reg_snapshot * snapshot)2075d63284e6SKumar Kartikeya Dwivedi static const char *diag_var_offset(struct bpf_verifier_env *env,
2076d63284e6SKumar Kartikeya Dwivedi 				   const struct bpf_diag_reg_snapshot *snapshot)
2077d63284e6SKumar Kartikeya Dwivedi {
2078d63284e6SKumar Kartikeya Dwivedi 	if (tnum_is_const(snapshot->var_off))
2079d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "at offset %lld", (s64)snapshot->var_off.value);
2080d63284e6SKumar Kartikeya Dwivedi 
2081d63284e6SKumar Kartikeya Dwivedi 	if (diag_snapshot_unknown(snapshot))
2082d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "with unknown offset");
2083d63284e6SKumar Kartikeya Dwivedi 
2084d63284e6SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env,
2085d63284e6SKumar Kartikeya Dwivedi 			    "with variable offset: known bits %#llx, unknown mask %#llx, %s",
2086d63284e6SKumar Kartikeya Dwivedi 			    snapshot->var_off.value, snapshot->var_off.mask,
2087d63284e6SKumar Kartikeya Dwivedi 			    diag_scalar_range(env, snapshot->r64));
2088d63284e6SKumar Kartikeya Dwivedi }
2089d63284e6SKumar Kartikeya Dwivedi 
diag_reg_map_name(const struct bpf_map * map)2090d63284e6SKumar Kartikeya Dwivedi static const char *diag_reg_map_name(const struct bpf_map *map)
2091d63284e6SKumar Kartikeya Dwivedi {
2092d63284e6SKumar Kartikeya Dwivedi 	if (!map || !map->name[0])
2093d63284e6SKumar Kartikeya Dwivedi 		return NULL;
2094d63284e6SKumar Kartikeya Dwivedi 
2095d63284e6SKumar Kartikeya Dwivedi 	return map->name;
2096d63284e6SKumar Kartikeya Dwivedi }
2097d63284e6SKumar Kartikeya Dwivedi 
diag_reg_snapshot(struct bpf_verifier_env * env,const struct bpf_diag_reg_snapshot * snapshot)2098d63284e6SKumar Kartikeya Dwivedi static const char *diag_reg_snapshot(struct bpf_verifier_env *env,
2099d63284e6SKumar Kartikeya Dwivedi 				     const struct bpf_diag_reg_snapshot *snapshot)
2100d63284e6SKumar Kartikeya Dwivedi {
2101d63284e6SKumar Kartikeya Dwivedi 	const char *type_name = reg_type_str(env, snapshot->type);
2102d63284e6SKumar Kartikeya Dwivedi 	const char *offset = diag_var_offset(env, snapshot);
2103d63284e6SKumar Kartikeya Dwivedi 	const char *btf = snapshot->btf && snapshot->btf_id ?
2104d63284e6SKumar Kartikeya Dwivedi 			  bpf_diag_fmt_btf_type(env, snapshot->btf, snapshot->btf_id) : NULL;
2105d63284e6SKumar Kartikeya Dwivedi 	const char *map_name;
2106d63284e6SKumar Kartikeya Dwivedi 
2107d63284e6SKumar Kartikeya Dwivedi 	if (snapshot->type == SCALAR_VALUE) {
2108d63284e6SKumar Kartikeya Dwivedi 		if (tnum_is_const(snapshot->var_off))
2109d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "integer scalar value %lld",
2110d63284e6SKumar Kartikeya Dwivedi 					    (s64)snapshot->var_off.value);
2111d63284e6SKumar Kartikeya Dwivedi 		if (diag_snapshot_unknown(snapshot))
2112d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "integer scalar with unknown value");
2113d63284e6SKumar Kartikeya Dwivedi 		if (cnum64_is_const(snapshot->r64))
2114d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "integer scalar value %lld",
2115d63284e6SKumar Kartikeya Dwivedi 					    cnum64_smin(snapshot->r64));
2116d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "integer scalar with %s",
2117d63284e6SKumar Kartikeya Dwivedi 				    diag_scalar_range(env, snapshot->r64));
2118d63284e6SKumar Kartikeya Dwivedi 	}
2119d63284e6SKumar Kartikeya Dwivedi 
2120d63284e6SKumar Kartikeya Dwivedi 	if (snapshot->type == NOT_INIT)
2121d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "uninitialized value");
2122d63284e6SKumar Kartikeya Dwivedi 
2123d63284e6SKumar Kartikeya Dwivedi 	if (base_type(snapshot->type) == PTR_TO_CTX)
2124d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "context pointer %s", offset);
2125d63284e6SKumar Kartikeya Dwivedi 
2126d63284e6SKumar Kartikeya Dwivedi 	if (base_type(snapshot->type) == PTR_TO_STACK)
2127d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "stack pointer %s", offset);
2128d63284e6SKumar Kartikeya Dwivedi 
2129d63284e6SKumar Kartikeya Dwivedi 	if (base_type(snapshot->type) == PTR_TO_MAP_VALUE) {
2130d63284e6SKumar Kartikeya Dwivedi 		const char *kind = type_may_be_null(snapshot->type) ? "nullable map value" :
2131d63284e6SKumar Kartikeya Dwivedi 								      "map value";
2132d63284e6SKumar Kartikeya Dwivedi 
2133d63284e6SKumar Kartikeya Dwivedi 		map_name = diag_reg_map_name(snapshot->map_ptr);
2134d63284e6SKumar Kartikeya Dwivedi 		if (map_name)
2135d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "%s from %s %s", kind, map_name, offset);
2136d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "%s %s", kind, offset);
2137d63284e6SKumar Kartikeya Dwivedi 	}
2138d63284e6SKumar Kartikeya Dwivedi 
2139d63284e6SKumar Kartikeya Dwivedi 	if (base_type(snapshot->type) == CONST_PTR_TO_MAP) {
2140d63284e6SKumar Kartikeya Dwivedi 		map_name = diag_reg_map_name(snapshot->map_ptr);
2141d63284e6SKumar Kartikeya Dwivedi 		if (map_name)
2142d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "map pointer for map %s", map_name);
2143d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "map pointer");
2144d63284e6SKumar Kartikeya Dwivedi 	}
2145d63284e6SKumar Kartikeya Dwivedi 
2146d63284e6SKumar Kartikeya Dwivedi 	if (type_is_non_owning_ref(snapshot->type)) {
2147d63284e6SKumar Kartikeya Dwivedi 		if (btf)
2148d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "borrowed allocated object pointer type=%s", btf);
2149d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "borrowed allocated object pointer");
2150d63284e6SKumar Kartikeya Dwivedi 	}
2151d63284e6SKumar Kartikeya Dwivedi 
2152d63284e6SKumar Kartikeya Dwivedi 	if (type_is_ptr_alloc_obj(snapshot->type)) {
2153d63284e6SKumar Kartikeya Dwivedi 		if (btf)
2154d63284e6SKumar Kartikeya Dwivedi 			return bpf_diag_fmt(env, "owned allocated object pointer type=%s", btf);
2155d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "owned allocated object pointer");
2156d63284e6SKumar Kartikeya Dwivedi 	}
2157d63284e6SKumar Kartikeya Dwivedi 
2158d63284e6SKumar Kartikeya Dwivedi 	if (base_type(snapshot->type) == PTR_TO_BTF_ID && btf)
2159d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "%s type=%s %s", type_name, btf, offset);
2160d63284e6SKumar Kartikeya Dwivedi 
2161d63284e6SKumar Kartikeya Dwivedi 	return bpf_diag_fmt(env, "%s %s", type_name, offset);
2162d63284e6SKumar Kartikeya Dwivedi }
2163d63284e6SKumar Kartikeya Dwivedi 
diag_mod_target_desc(struct bpf_verifier_env * env,const struct bpf_diag_mod_target * target)2164d63284e6SKumar Kartikeya Dwivedi static const char *diag_mod_target_desc(struct bpf_verifier_env *env,
2165d63284e6SKumar Kartikeya Dwivedi 					const struct bpf_diag_mod_target *target)
2166d63284e6SKumar Kartikeya Dwivedi {
2167d63284e6SKumar Kartikeya Dwivedi 	switch (target->kind) {
2168d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_REG:
2169d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "R%u", target->regno);
2170d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_ARG:
217109a0c2d6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "*(R11-%u)", (target->stack_arg + 1) * BPF_REG_SIZE);
2172d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_SLOT:
2173d63284e6SKumar Kartikeya Dwivedi 		return bpf_diag_fmt(env, "stack slot fp%d", -(target->spi + 1) * BPF_REG_SIZE);
2174d63284e6SKumar Kartikeya Dwivedi 	default:
2175d63284e6SKumar Kartikeya Dwivedi 		return "value";
2176d63284e6SKumar Kartikeya Dwivedi 	}
2177d63284e6SKumar Kartikeya Dwivedi }
2178d63284e6SKumar Kartikeya Dwivedi 
diag_print_mod(struct bpf_verifier_env * env,const struct bpf_diag_history_event * event)2179d63284e6SKumar Kartikeya Dwivedi static void diag_print_mod(struct bpf_verifier_env *env, const struct bpf_diag_history_event *event)
2180d63284e6SKumar Kartikeya Dwivedi {
2181d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_mod_target *target = &event->mod.target;
2182d63284e6SKumar Kartikeya Dwivedi 	const char *target_desc, *reason = NULL, *old, *new;
2183d63284e6SKumar Kartikeya Dwivedi 	const char *label = "update";
2184d63284e6SKumar Kartikeya Dwivedi 
2185d63284e6SKumar Kartikeya Dwivedi 	if (target->kind == BPF_DIAG_MOD_TARGET_STACK_RANGE) {
2186d63284e6SKumar Kartikeya Dwivedi 		bpf_diag_source(
2187d63284e6SKumar Kartikeya Dwivedi 			env, event->insn_idx, "invalidated",
2188d63284e6SKumar Kartikeya Dwivedi 			"variable-offset stack write may affect bytes fp%d through fp%d",
2189d63284e6SKumar Kartikeya Dwivedi 			target->range.min_off, target->range.max_off - 1);
2190d63284e6SKumar Kartikeya Dwivedi 		return;
2191d63284e6SKumar Kartikeya Dwivedi 	}
2192d63284e6SKumar Kartikeya Dwivedi 
2193d63284e6SKumar Kartikeya Dwivedi 	old = diag_reg_snapshot(env, &event->mod.old);
2194d63284e6SKumar Kartikeya Dwivedi 	new = diag_reg_snapshot(env, &event->mod.new);
2195d63284e6SKumar Kartikeya Dwivedi 	target_desc = diag_mod_target_desc(env, target);
2196d63284e6SKumar Kartikeya Dwivedi 
2197d63284e6SKumar Kartikeya Dwivedi 	switch (event->mod.reason) {
2198d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_REF_RELEASE:
2199d63284e6SKumar Kartikeya Dwivedi 		reason = target->kind == BPF_DIAG_MOD_TARGET_REG ? "resource release invalidated "
2200d63284e6SKumar Kartikeya Dwivedi 								   "this pointer" :
2201d63284e6SKumar Kartikeya Dwivedi 								   "resource release invalidated "
2202d63284e6SKumar Kartikeya Dwivedi 								   "this value";
2203d63284e6SKumar Kartikeya Dwivedi 		break;
2204d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_PKT_DATA_CHANGE:
2205d63284e6SKumar Kartikeya Dwivedi 		reason = "packet data may have moved";
2206d63284e6SKumar Kartikeya Dwivedi 		break;
2207d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_NON_OWN_REF:
2208d63284e6SKumar Kartikeya Dwivedi 		reason = "leaving the protected region invalidated this borrowed pointer";
2209d63284e6SKumar Kartikeya Dwivedi 		break;
2210d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_CALLER_SAVED:
2211d63284e6SKumar Kartikeya Dwivedi 		reason = target->kind == BPF_DIAG_MOD_TARGET_STACK_ARG ?
2212d63284e6SKumar Kartikeya Dwivedi 			 "call invalidated this outgoing stack argument" :
2213d63284e6SKumar Kartikeya Dwivedi 			 "call invalidated this caller-saved register";
2214d63284e6SKumar Kartikeya Dwivedi 		break;
2215d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_WRITE:
2216d63284e6SKumar Kartikeya Dwivedi 		if (target->kind == BPF_DIAG_MOD_TARGET_STACK_SLOT)
2217d63284e6SKumar Kartikeya Dwivedi 			reason = "a later stack write overwrote this spilled value";
2218d63284e6SKumar Kartikeya Dwivedi 		break;
2219d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_SPILL:
2220d63284e6SKumar Kartikeya Dwivedi 		label = "spilled";
2221d63284e6SKumar Kartikeya Dwivedi 		break;
2222d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_VAR_WRITE:
2223d63284e6SKumar Kartikeya Dwivedi 	default:
2224d63284e6SKumar Kartikeya Dwivedi 		break;
2225d63284e6SKumar Kartikeya Dwivedi 	}
2226d63284e6SKumar Kartikeya Dwivedi 
2227d63284e6SKumar Kartikeya Dwivedi 	if (reason) {
2228d63284e6SKumar Kartikeya Dwivedi 		bpf_diag_source(env, event->insn_idx, "invalidated",
2229d63284e6SKumar Kartikeya Dwivedi 				"%s: %s; previous value was %s", target_desc, reason, old);
2230d63284e6SKumar Kartikeya Dwivedi 		return;
2231d63284e6SKumar Kartikeya Dwivedi 	}
2232d63284e6SKumar Kartikeya Dwivedi 
2233d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, event->insn_idx, label, "%s changed from %s to %s", target_desc,
2234d63284e6SKumar Kartikeya Dwivedi 			old, new);
2235d63284e6SKumar Kartikeya Dwivedi }
2236d63284e6SKumar Kartikeya Dwivedi 
diag_print_ref_event(struct bpf_verifier_env * env,const struct bpf_diag_history_event * event)2237d63284e6SKumar Kartikeya Dwivedi static void diag_print_ref_event(struct bpf_verifier_env *env,
2238d63284e6SKumar Kartikeya Dwivedi 				 const struct bpf_diag_history_event *event)
2239d63284e6SKumar Kartikeya Dwivedi {
2240d63284e6SKumar Kartikeya Dwivedi 	const char *label;
2241d63284e6SKumar Kartikeya Dwivedi 
2242d63284e6SKumar Kartikeya Dwivedi 	label = event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE ? "acquired" : "released";
2243d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, event->insn_idx, label, "owned resource (id=%u)",
2244d63284e6SKumar Kartikeya Dwivedi 			event->ref.ref_id);
2245d63284e6SKumar Kartikeya Dwivedi }
2246d63284e6SKumar Kartikeya Dwivedi 
diag_context_name(enum bpf_diag_context_kind kind)2247d63284e6SKumar Kartikeya Dwivedi static const char *diag_context_name(enum bpf_diag_context_kind kind)
2248d63284e6SKumar Kartikeya Dwivedi {
2249d63284e6SKumar Kartikeya Dwivedi 	switch (kind) {
2250d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_RCU:
2251d63284e6SKumar Kartikeya Dwivedi 		return "RCU read lock region";
2252d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_PREEMPT:
2253d63284e6SKumar Kartikeya Dwivedi 		return "non-preemptible region";
2254d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_IRQ:
2255d63284e6SKumar Kartikeya Dwivedi 		return "IRQ-disabled region";
2256d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_LOCK:
2257d63284e6SKumar Kartikeya Dwivedi 		return "lock region";
2258d63284e6SKumar Kartikeya Dwivedi 	case BPF_DIAG_CONTEXT_NONE:
2259d63284e6SKumar Kartikeya Dwivedi 	default:
226099a6a288SKumar Kartikeya Dwivedi 		return "non-sleepable program";
2261d63284e6SKumar Kartikeya Dwivedi 	}
2262d63284e6SKumar Kartikeya Dwivedi }
2263d63284e6SKumar Kartikeya Dwivedi 
diag_print_context_event(struct bpf_verifier_env * env,const struct bpf_diag_history_event * event)2264d63284e6SKumar Kartikeya Dwivedi static void diag_print_context_event(struct bpf_verifier_env *env,
2265d63284e6SKumar Kartikeya Dwivedi 				     const struct bpf_diag_history_event *event)
2266d63284e6SKumar Kartikeya Dwivedi {
2267d63284e6SKumar Kartikeya Dwivedi 	bpf_diag_source(env, event->insn_idx, "context", "%s %s; depth is now %u",
2268d63284e6SKumar Kartikeya Dwivedi 			event->ctx.enter ? "entered" : "left",
2269d63284e6SKumar Kartikeya Dwivedi 			diag_context_name(event->ctx.kind), event->ctx.depth);
2270d63284e6SKumar Kartikeya Dwivedi }
2271d63284e6SKumar Kartikeya Dwivedi 
diag_print_history(struct bpf_verifier_env * env,const struct bpf_diag_history_opts * opts)2272d63284e6SKumar Kartikeya Dwivedi static void diag_print_history(struct bpf_verifier_env *env,
2273d63284e6SKumar Kartikeya Dwivedi 			       const struct bpf_diag_history_opts *opts)
2274d63284e6SKumar Kartikeya Dwivedi {
2275d63284e6SKumar Kartikeya Dwivedi 	const struct bpf_diag_history_event *event;
2276d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_history_filter filter = {
2277d63284e6SKumar Kartikeya Dwivedi 		.opts = opts,
2278d63284e6SKumar Kartikeya Dwivedi 	};
2279d63284e6SKumar Kartikeya Dwivedi 	struct bpf_diag_log *log;
2280d63284e6SKumar Kartikeya Dwivedi 	struct diag_fmt_mark mark;
2281d63284e6SKumar Kartikeya Dwivedi 	bool first = true;
2282d63284e6SKumar Kartikeya Dwivedi 	int start_idx;
2283d63284e6SKumar Kartikeya Dwivedi 	u32 i, visible_cnt = 0, visible_idx = 0;
2284d63284e6SKumar Kartikeya Dwivedi 
2285d63284e6SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
2286d63284e6SKumar Kartikeya Dwivedi 		return;
2287d63284e6SKumar Kartikeya Dwivedi 
2288d63284e6SKumar Kartikeya Dwivedi 	if (!env->diag)
2289d63284e6SKumar Kartikeya Dwivedi 		return;
2290d63284e6SKumar Kartikeya Dwivedi 	log = &env->diag->log;
2291d63284e6SKumar Kartikeya Dwivedi 
2292d63284e6SKumar Kartikeya Dwivedi 	diag_build_lineage(env, log, &filter);
2293d63284e6SKumar Kartikeya Dwivedi 
2294d63284e6SKumar Kartikeya Dwivedi 	start_idx = diag_history_start_idx(log, &filter);
2295d63284e6SKumar Kartikeya Dwivedi 	for (i = start_idx; i < log->cnt; i++) {
2296d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i)];
2297d63284e6SKumar Kartikeya Dwivedi 		if (diag_history_event_visible(event, &filter))
2298d63284e6SKumar Kartikeya Dwivedi 			visible_cnt++;
2299d63284e6SKumar Kartikeya Dwivedi 	}
2300d63284e6SKumar Kartikeya Dwivedi 
2301d63284e6SKumar Kartikeya Dwivedi 	if (!visible_cnt && !log->first_seq && opts->scope == BPF_DIAG_HISTORY_SCOPE_STACK_ARG)
2302d63284e6SKumar Kartikeya Dwivedi 		return;
2303d63284e6SKumar Kartikeya Dwivedi 
2304d63284e6SKumar Kartikeya Dwivedi 	diag_section(env, "Causal path");
2305d63284e6SKumar Kartikeya Dwivedi 	mark = diag_fmt_save(env);
2306d63284e6SKumar Kartikeya Dwivedi 	for (i = start_idx; i < log->cnt; i++) {
2307d63284e6SKumar Kartikeya Dwivedi 		event = &log->events[log_pos(log, i)];
2308d63284e6SKumar Kartikeya Dwivedi 		if (!diag_history_event_visible(event, &filter))
2309d63284e6SKumar Kartikeya Dwivedi 			continue;
2310d63284e6SKumar Kartikeya Dwivedi 
2311d63284e6SKumar Kartikeya Dwivedi 		diag_fmt_restore(env, mark);
2312d63284e6SKumar Kartikeya Dwivedi 		if (visible_cnt > BPF_DIAG_HISTORY_RENDER_MAX &&
2313d63284e6SKumar Kartikeya Dwivedi 		    visible_idx >= BPF_DIAG_HISTORY_RENDER_MAX / 2 &&
2314d63284e6SKumar Kartikeya Dwivedi 		    visible_idx < visible_cnt - BPF_DIAG_HISTORY_RENDER_MAX / 2) {
2315d63284e6SKumar Kartikeya Dwivedi 			if (visible_idx++ != BPF_DIAG_HISTORY_RENDER_MAX / 2)
2316d63284e6SKumar Kartikeya Dwivedi 				continue;
2317d63284e6SKumar Kartikeya Dwivedi 			if (!first)
2318d63284e6SKumar Kartikeya Dwivedi 				diag_write(env, "\n");
2319d63284e6SKumar Kartikeya Dwivedi 			first = false;
2320d63284e6SKumar Kartikeya Dwivedi 			diag_write(env, "  %u intermediate causal-history events omitted\n",
2321d63284e6SKumar Kartikeya Dwivedi 				   visible_cnt - BPF_DIAG_HISTORY_RENDER_MAX);
2322d63284e6SKumar Kartikeya Dwivedi 			continue;
2323d63284e6SKumar Kartikeya Dwivedi 		}
2324d63284e6SKumar Kartikeya Dwivedi 		visible_idx++;
2325d63284e6SKumar Kartikeya Dwivedi 
2326d63284e6SKumar Kartikeya Dwivedi 		if (!first)
2327d63284e6SKumar Kartikeya Dwivedi 			diag_write(env, "\n");
2328d63284e6SKumar Kartikeya Dwivedi 		first = false;
2329d63284e6SKumar Kartikeya Dwivedi 
2330d63284e6SKumar Kartikeya Dwivedi 		switch (event->kind) {
2331d63284e6SKumar Kartikeya Dwivedi 		case BPF_DIAG_HISTORY_BRANCH:
2332d63284e6SKumar Kartikeya Dwivedi 			bpf_diag_source(env, event->insn_idx, "branch",
2333d63284e6SKumar Kartikeya Dwivedi 					"took the %s branch of this conditional, goto %s",
2334d63284e6SKumar Kartikeya Dwivedi 					event->branch.cond_true ? "true" : "false",
2335d63284e6SKumar Kartikeya Dwivedi 					event->branch.cond_true ? "followed" : "not followed");
2336d63284e6SKumar Kartikeya Dwivedi 			break;
2337d63284e6SKumar Kartikeya Dwivedi 		case BPF_DIAG_HISTORY_MOD:
2338d63284e6SKumar Kartikeya Dwivedi 			diag_print_mod(env, event);
2339d63284e6SKumar Kartikeya Dwivedi 			break;
2340d63284e6SKumar Kartikeya Dwivedi 		case BPF_DIAG_HISTORY_REF_ACQUIRE:
2341d63284e6SKumar Kartikeya Dwivedi 		case BPF_DIAG_HISTORY_REF_RELEASE:
2342d63284e6SKumar Kartikeya Dwivedi 			diag_print_ref_event(env, event);
2343d63284e6SKumar Kartikeya Dwivedi 			break;
2344d63284e6SKumar Kartikeya Dwivedi 		case BPF_DIAG_HISTORY_CONTEXT:
2345d63284e6SKumar Kartikeya Dwivedi 			diag_print_context_event(env, event);
2346d63284e6SKumar Kartikeya Dwivedi 			break;
2347d63284e6SKumar Kartikeya Dwivedi 		default:
2348d63284e6SKumar Kartikeya Dwivedi 			break;
2349d63284e6SKumar Kartikeya Dwivedi 		}
2350d63284e6SKumar Kartikeya Dwivedi 	}
2351d63284e6SKumar Kartikeya Dwivedi 
2352d63284e6SKumar Kartikeya Dwivedi 	if (!visible_cnt)
2353d63284e6SKumar Kartikeya Dwivedi 		diag_write(env, "  no retained diagnostic events on this path\n");
2354d63284e6SKumar Kartikeya Dwivedi 	if (log->first_seq)
2355d63284e6SKumar Kartikeya Dwivedi 		diag_write(env, "  %llu older causal-history event%s not retained because diagnostic "
2356d63284e6SKumar Kartikeya Dwivedi 			   "event storage reached capacity\n",
2357d63284e6SKumar Kartikeya Dwivedi 			   log->first_seq, log->first_seq == 1 ? "" : "s");
2358d63284e6SKumar Kartikeya Dwivedi 	diag_fmt_restore(env, mark);
2359d63284e6SKumar Kartikeya Dwivedi }
2360