xref: /linux/kernel/bpf/diagnostics.c (revision 956a66e5c33fb53003ca2bc043a90ff0b671b3a5)
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>
11b9c5d822SKumar Kartikeya Dwivedi #include <linux/slab.h>
125ad74616SKumar Kartikeya Dwivedi #include <linux/stdarg.h>
13b9c5d822SKumar Kartikeya Dwivedi #include <linux/string.h>
145ad74616SKumar Kartikeya Dwivedi 
15b9c5d822SKumar Kartikeya Dwivedi #include "disasm.h"
165ad74616SKumar Kartikeya Dwivedi #include "diagnostics.h"
175ad74616SKumar Kartikeya Dwivedi 
18b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_WIDTH 100
19b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT 2
20b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT_CNT (1 + BPF_DIAG_CONTEXT * 2)
21b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_SOURCE_LANE_WIDTH 88
22b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TAB_WIDTH 8
23b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_CHUNK_SIZE (PAGE_SIZE - sizeof(struct diag_fmt_chunk))
24b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_BUF_SIZE 256
25daf82487SKumar Kartikeya Dwivedi #define BPF_DIAG_EVENT_LOG_MAX_SIZE (64U << 20)
26b9c5d822SKumar Kartikeya Dwivedi #define DISASM_LINE_LEN 160
27b9c5d822SKumar Kartikeya Dwivedi 
28af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_target_kind {
29af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_NONE,
30af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_REG,
31af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_ARG,
32af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_SLOT,
33af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_MOD_TARGET_STACK_RANGE,
34af4ea6e2SKumar Kartikeya Dwivedi };
35af4ea6e2SKumar Kartikeya Dwivedi 
36af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target {
37af4ea6e2SKumar Kartikeya Dwivedi 	u32 frame_id;
38af4ea6e2SKumar Kartikeya Dwivedi 	union {
39af4ea6e2SKumar Kartikeya Dwivedi 		struct {
40af4ea6e2SKumar Kartikeya Dwivedi 			s16 min_off;
41af4ea6e2SKumar Kartikeya Dwivedi 			s16 max_off;
42af4ea6e2SKumar Kartikeya Dwivedi 		} range;
43af4ea6e2SKumar Kartikeya Dwivedi 		u16 spi;
44af4ea6e2SKumar Kartikeya Dwivedi 		u8 regno;
45af4ea6e2SKumar Kartikeya Dwivedi 		u8 stack_arg;
46af4ea6e2SKumar Kartikeya Dwivedi 	};
47af4ea6e2SKumar Kartikeya Dwivedi 	u8 frameno;
48af4ea6e2SKumar Kartikeya Dwivedi 	u8 kind;
49af4ea6e2SKumar Kartikeya Dwivedi };
50af4ea6e2SKumar Kartikeya Dwivedi 
51af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_reg_target(u32 frame_id, u8 frameno, u8 regno)
52af4ea6e2SKumar Kartikeya Dwivedi {
53af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
54af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
55af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
56af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_REG,
57af4ea6e2SKumar Kartikeya Dwivedi 		.regno = regno,
58af4ea6e2SKumar Kartikeya Dwivedi 	};
59af4ea6e2SKumar Kartikeya Dwivedi }
60af4ea6e2SKumar Kartikeya Dwivedi 
61af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_arg_target(u32 frame_id, u8 frameno, u8 slot)
62af4ea6e2SKumar Kartikeya Dwivedi {
63af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
64af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
65af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
66af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_STACK_ARG,
67af4ea6e2SKumar Kartikeya Dwivedi 		.stack_arg = slot,
68af4ea6e2SKumar Kartikeya Dwivedi 	};
69af4ea6e2SKumar Kartikeya Dwivedi }
70af4ea6e2SKumar Kartikeya Dwivedi 
71af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_slot_target(u32 frame_id, u8 frameno, u16 spi)
72af4ea6e2SKumar Kartikeya Dwivedi {
73af4ea6e2SKumar Kartikeya Dwivedi 	return (struct bpf_diag_mod_target){
74af4ea6e2SKumar Kartikeya Dwivedi 		.frame_id = frame_id,
75af4ea6e2SKumar Kartikeya Dwivedi 		.frameno = frameno,
76af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_MOD_TARGET_STACK_SLOT,
77af4ea6e2SKumar Kartikeya Dwivedi 		.spi = spi,
78af4ea6e2SKumar Kartikeya Dwivedi 	};
79af4ea6e2SKumar Kartikeya Dwivedi }
80af4ea6e2SKumar Kartikeya Dwivedi 
81af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_range_target(u32 frame_id, u8 frameno,
82af4ea6e2SKumar Kartikeya Dwivedi 							  s16 min_off, s16 max_off)
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_RANGE,
88af4ea6e2SKumar Kartikeya Dwivedi 		.range.min_off = min_off,
89af4ea6e2SKumar Kartikeya Dwivedi 		.range.max_off = max_off,
90af4ea6e2SKumar Kartikeya Dwivedi 	};
91af4ea6e2SKumar Kartikeya Dwivedi }
92af4ea6e2SKumar Kartikeya Dwivedi 
93af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot {
94af4ea6e2SKumar Kartikeya Dwivedi 	u32 type;
95af4ea6e2SKumar Kartikeya Dwivedi 	u32 btf_id;
96af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_map *map_ptr;
97af4ea6e2SKumar Kartikeya Dwivedi 	const struct btf *btf;
98af4ea6e2SKumar Kartikeya Dwivedi 	struct tnum var_off;
99af4ea6e2SKumar Kartikeya Dwivedi 	struct cnum64 r64;
100af4ea6e2SKumar Kartikeya Dwivedi };
101af4ea6e2SKumar Kartikeya Dwivedi 
102daf82487SKumar Kartikeya Dwivedi enum bpf_diag_history_kind {
103daf82487SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_BRANCH,
104af4ea6e2SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_MOD,
1059ecd7030SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_REF_ACQUIRE,
1069ecd7030SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_REF_RELEASE,
107*956a66e5SKumar Kartikeya Dwivedi 	BPF_DIAG_HISTORY_CONTEXT,
108daf82487SKumar Kartikeya Dwivedi };
109daf82487SKumar Kartikeya Dwivedi 
110daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event {
111daf82487SKumar Kartikeya Dwivedi 	u32 insn_idx : 24;
112daf82487SKumar Kartikeya Dwivedi 	u32 kind : 8;
113daf82487SKumar Kartikeya Dwivedi 	u8 in_lineage : 1;
114daf82487SKumar Kartikeya Dwivedi 	union {
115daf82487SKumar Kartikeya Dwivedi 		struct {
116daf82487SKumar Kartikeya Dwivedi 			bool cond_true;
117daf82487SKumar Kartikeya Dwivedi 		} branch;
118af4ea6e2SKumar Kartikeya Dwivedi 		struct {
119af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_mod_target target;
120af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_mod_target origin;
121af4ea6e2SKumar Kartikeya Dwivedi 			struct bpf_diag_reg_snapshot old, new;
122af4ea6e2SKumar Kartikeya Dwivedi 			u8 reason;
123af4ea6e2SKumar Kartikeya Dwivedi 			bool origin_valid;
124af4ea6e2SKumar Kartikeya Dwivedi 		} mod;
1259ecd7030SKumar Kartikeya Dwivedi 		struct {
1269ecd7030SKumar Kartikeya Dwivedi 			u32 ref_id;
1279ecd7030SKumar Kartikeya Dwivedi 		} ref;
128*956a66e5SKumar Kartikeya Dwivedi 		struct {
129*956a66e5SKumar Kartikeya Dwivedi 			u32 depth;
130*956a66e5SKumar Kartikeya Dwivedi 			u8 kind;
131*956a66e5SKumar Kartikeya Dwivedi 			bool enter;
132*956a66e5SKumar Kartikeya Dwivedi 		} ctx;
133daf82487SKumar Kartikeya Dwivedi 	};
134daf82487SKumar Kartikeya Dwivedi };
135daf82487SKumar Kartikeya Dwivedi 
136b9c5d822SKumar Kartikeya Dwivedi struct disasm_line {
137b9c5d822SKumar Kartikeya Dwivedi 	char text[DISASM_LINE_LEN];
138b9c5d822SKumar Kartikeya Dwivedi 	int idx;
139b9c5d822SKumar Kartikeya Dwivedi 	bool valid;
140b9c5d822SKumar Kartikeya Dwivedi };
141b9c5d822SKumar Kartikeya Dwivedi 
142b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx {
143b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_verifier_env *env;
144b9c5d822SKumar Kartikeya Dwivedi 	struct seq_buf seq;
145b9c5d822SKumar Kartikeya Dwivedi };
146b9c5d822SKumar Kartikeya Dwivedi 
147b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk {
148b9c5d822SKumar Kartikeya Dwivedi 	struct list_head node;
149b9c5d822SKumar Kartikeya Dwivedi 	struct seq_buf seq;
150b9c5d822SKumar Kartikeya Dwivedi 	char data[];
151b9c5d822SKumar Kartikeya Dwivedi };
152b9c5d822SKumar Kartikeya Dwivedi 
153b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark {
154b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
155b9c5d822SKumar Kartikeya Dwivedi 	size_t len;
156b9c5d822SKumar Kartikeya Dwivedi };
157b9c5d822SKumar Kartikeya Dwivedi 
158daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log {
159daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event *events;
160daf82487SKumar Kartikeya Dwivedi 	/* Sequence number of the oldest retained event on the active path. */
161daf82487SKumar Kartikeya Dwivedi 	u64 first_seq;
162daf82487SKumar Kartikeya Dwivedi 	u32 cnt;
163daf82487SKumar Kartikeya Dwivedi 	u32 cap;
164daf82487SKumar Kartikeya Dwivedi 	u32 head;
165daf82487SKumar Kartikeya Dwivedi 	bool growth_failed;
166daf82487SKumar Kartikeya Dwivedi };
167daf82487SKumar Kartikeya Dwivedi 
168b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch {
169b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source source_lines[BPF_DIAG_CONTEXT_CNT];
170b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_line disasm_lines[BPF_DIAG_CONTEXT_CNT];
171b9c5d822SKumar Kartikeya Dwivedi };
172b9c5d822SKumar Kartikeya Dwivedi 
173af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope {
174af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_reg_state target_reg_snapshot;
175af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
176af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target origin;
177af4ea6e2SKumar Kartikeya Dwivedi 	enum bpf_diag_mod_reason reason;
178af4ea6e2SKumar Kartikeya Dwivedi 	u32 insn_idx;
179af4ea6e2SKumar Kartikeya Dwivedi 	bool active;
180af4ea6e2SKumar Kartikeya Dwivedi 	bool origin_valid;
181af4ea6e2SKumar Kartikeya Dwivedi };
182af4ea6e2SKumar Kartikeya Dwivedi 
183b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag {
184daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log log;
185b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag_scratch scratch;
186b9c5d822SKumar Kartikeya Dwivedi 	struct list_head fmt_chunks;
187af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_scope mod;
188af4ea6e2SKumar Kartikeya Dwivedi 	u32 frame_id_gen;
189b9c5d822SKumar Kartikeya Dwivedi };
190b9c5d822SKumar Kartikeya Dwivedi 
1915ad74616SKumar Kartikeya Dwivedi bool bpf_diag_enabled(const struct bpf_verifier_env *env)
1925ad74616SKumar Kartikeya Dwivedi {
1935ad74616SKumar Kartikeya Dwivedi 	return env->log.level & BPF_LOG_LEVEL;
1945ad74616SKumar Kartikeya Dwivedi }
1955ad74616SKumar Kartikeya Dwivedi 
1965ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3);
1975ad74616SKumar Kartikeya Dwivedi 
198b9c5d822SKumar Kartikeya Dwivedi int bpf_diag_init(struct bpf_verifier_env *env)
199b9c5d822SKumar Kartikeya Dwivedi {
200b9c5d822SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
201b9c5d822SKumar Kartikeya Dwivedi 		return 0;
202b9c5d822SKumar Kartikeya Dwivedi 
203b9c5d822SKumar Kartikeya Dwivedi 	env->diag = kzalloc_obj(struct bpf_diag, GFP_KERNEL_ACCOUNT);
204b9c5d822SKumar Kartikeya Dwivedi 	if (!env->diag)
205b9c5d822SKumar Kartikeya Dwivedi 		return -ENOMEM;
206b9c5d822SKumar Kartikeya Dwivedi 
207b9c5d822SKumar Kartikeya Dwivedi 	INIT_LIST_HEAD(&env->diag->fmt_chunks);
208b9c5d822SKumar Kartikeya Dwivedi 	return 0;
209b9c5d822SKumar Kartikeya Dwivedi }
210b9c5d822SKumar Kartikeya Dwivedi 
211af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_init_frame(struct bpf_verifier_env *env, struct bpf_func_state *state)
212af4ea6e2SKumar Kartikeya Dwivedi {
213af4ea6e2SKumar Kartikeya Dwivedi 	if (env->diag)
214af4ea6e2SKumar Kartikeya Dwivedi 		state->diag_frame_id = ++env->diag->frame_id_gen;
215af4ea6e2SKumar Kartikeya Dwivedi }
216af4ea6e2SKumar Kartikeya Dwivedi 
217b9c5d822SKumar Kartikeya Dwivedi static char *diag_fmt_alloc(struct bpf_verifier_env *env, size_t size)
218b9c5d822SKumar Kartikeya Dwivedi {
219b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
220b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
221b9c5d822SKumar Kartikeya Dwivedi 	size_t capacity, available;
222b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
223b9c5d822SKumar Kartikeya Dwivedi 
224b9c5d822SKumar Kartikeya Dwivedi 	if (!diag || !size || size > INT_MAX)
225b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
226b9c5d822SKumar Kartikeya Dwivedi 
227b9c5d822SKumar Kartikeya Dwivedi 	if (!list_empty(&diag->fmt_chunks)) {
228b9c5d822SKumar Kartikeya Dwivedi 		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
229b9c5d822SKumar Kartikeya Dwivedi 		available = seq_buf_get_buf(&chunk->seq, &buf);
230b9c5d822SKumar Kartikeya Dwivedi 		if (available >= size)
231b9c5d822SKumar Kartikeya Dwivedi 			goto commit;
232b9c5d822SKumar Kartikeya Dwivedi 	}
233b9c5d822SKumar Kartikeya Dwivedi 
234b9c5d822SKumar Kartikeya Dwivedi 	capacity = max_t(size_t, BPF_DIAG_FMT_CHUNK_SIZE, size);
235b9c5d822SKumar Kartikeya Dwivedi 	chunk = kmalloc(struct_size(chunk, data, capacity), GFP_KERNEL_ACCOUNT);
236b9c5d822SKumar Kartikeya Dwivedi 	if (!chunk)
237b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
238b9c5d822SKumar Kartikeya Dwivedi 
239b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_init(&chunk->seq, chunk->data, capacity);
240b9c5d822SKumar Kartikeya Dwivedi 	list_add_tail(&chunk->node, &diag->fmt_chunks);
241b9c5d822SKumar Kartikeya Dwivedi 	available = seq_buf_get_buf(&chunk->seq, &buf);
242b9c5d822SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(available < size))
243b9c5d822SKumar Kartikeya Dwivedi 		return NULL;
244b9c5d822SKumar Kartikeya Dwivedi 
245b9c5d822SKumar Kartikeya Dwivedi commit:
246b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_commit(&chunk->seq, size);
247b9c5d822SKumar Kartikeya Dwivedi 	return buf;
248b9c5d822SKumar Kartikeya Dwivedi }
249b9c5d822SKumar Kartikeya Dwivedi 
250b9c5d822SKumar Kartikeya Dwivedi char *bpf_diag_fmt_buf(struct bpf_verifier_env *env, size_t size)
251b9c5d822SKumar Kartikeya Dwivedi {
252b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
253b9c5d822SKumar Kartikeya Dwivedi 
254b9c5d822SKumar Kartikeya Dwivedi 	buf = diag_fmt_alloc(env, size);
255b9c5d822SKumar Kartikeya Dwivedi 	if (buf)
256b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
257b9c5d822SKumar Kartikeya Dwivedi 	return buf;
258b9c5d822SKumar Kartikeya Dwivedi }
259b9c5d822SKumar Kartikeya Dwivedi 
260b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list args)
261b9c5d822SKumar Kartikeya Dwivedi {
262b9c5d822SKumar Kartikeya Dwivedi 	va_list copy;
263b9c5d822SKumar Kartikeya Dwivedi 	char *buf;
264b9c5d822SKumar Kartikeya Dwivedi 	int len;
265b9c5d822SKumar Kartikeya Dwivedi 
266b9c5d822SKumar Kartikeya Dwivedi 	va_copy(copy, args);
267b9c5d822SKumar Kartikeya Dwivedi 	len = vsnprintf(NULL, 0, fmt, copy);
268b9c5d822SKumar Kartikeya Dwivedi 	va_end(copy);
269b9c5d822SKumar Kartikeya Dwivedi 	if (len < 0 || len == INT_MAX)
270b9c5d822SKumar Kartikeya Dwivedi 		return "";
271b9c5d822SKumar Kartikeya Dwivedi 
272b9c5d822SKumar Kartikeya Dwivedi 	buf = diag_fmt_alloc(env, len + 1);
273b9c5d822SKumar Kartikeya Dwivedi 	if (buf)
274b9c5d822SKumar Kartikeya Dwivedi 		vsnprintf(buf, len + 1, fmt, args);
275b9c5d822SKumar Kartikeya Dwivedi 	return buf ?: "";
276b9c5d822SKumar Kartikeya Dwivedi }
277b9c5d822SKumar Kartikeya Dwivedi 
278b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...)
279b9c5d822SKumar Kartikeya Dwivedi {
280b9c5d822SKumar Kartikeya Dwivedi 	const char *buf;
281b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
282b9c5d822SKumar Kartikeya Dwivedi 
283b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
284b9c5d822SKumar Kartikeya Dwivedi 	buf = bpf_diag_vfmt(env, fmt, args);
285b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
286b9c5d822SKumar Kartikeya Dwivedi 	return buf;
287b9c5d822SKumar Kartikeya Dwivedi }
288b9c5d822SKumar Kartikeya Dwivedi 
289b9c5d822SKumar Kartikeya Dwivedi static struct diag_fmt_mark diag_fmt_save(struct bpf_verifier_env *env)
290b9c5d822SKumar Kartikeya Dwivedi {
291b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
292b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_mark mark = {};
293b9c5d822SKumar Kartikeya Dwivedi 
294b9c5d822SKumar Kartikeya Dwivedi 	if (!diag || list_empty(&diag->fmt_chunks))
295b9c5d822SKumar Kartikeya Dwivedi 		return mark;
296b9c5d822SKumar Kartikeya Dwivedi 
297b9c5d822SKumar Kartikeya Dwivedi 	mark.chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
298b9c5d822SKumar Kartikeya Dwivedi 	mark.len = mark.chunk->seq.len;
299b9c5d822SKumar Kartikeya Dwivedi 	return mark;
300b9c5d822SKumar Kartikeya Dwivedi }
301b9c5d822SKumar Kartikeya Dwivedi 
302b9c5d822SKumar Kartikeya Dwivedi static void diag_fmt_restore(struct bpf_verifier_env *env, struct diag_fmt_mark mark)
303b9c5d822SKumar Kartikeya Dwivedi {
304b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
305b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_chunk *chunk;
306b9c5d822SKumar Kartikeya Dwivedi 
307b9c5d822SKumar Kartikeya Dwivedi 	if (!diag)
308b9c5d822SKumar Kartikeya Dwivedi 		return;
309b9c5d822SKumar Kartikeya Dwivedi 
310b9c5d822SKumar Kartikeya Dwivedi 	while (!list_empty(&diag->fmt_chunks)) {
311b9c5d822SKumar Kartikeya Dwivedi 		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
312b9c5d822SKumar Kartikeya Dwivedi 		if (chunk == mark.chunk)
313b9c5d822SKumar Kartikeya Dwivedi 			break;
314b9c5d822SKumar Kartikeya Dwivedi 		list_del(&chunk->node);
315b9c5d822SKumar Kartikeya Dwivedi 		kfree(chunk);
316b9c5d822SKumar Kartikeya Dwivedi 	}
317b9c5d822SKumar Kartikeya Dwivedi 
318b9c5d822SKumar Kartikeya Dwivedi 	if (mark.chunk) {
319b9c5d822SKumar Kartikeya Dwivedi 		mark.chunk->seq.len = mark.len;
320b9c5d822SKumar Kartikeya Dwivedi 		seq_buf_str(&mark.chunk->seq);
321b9c5d822SKumar Kartikeya Dwivedi 	}
322b9c5d822SKumar Kartikeya Dwivedi }
323b9c5d822SKumar Kartikeya Dwivedi 
324b9c5d822SKumar Kartikeya Dwivedi void bpf_diag_free(struct bpf_verifier_env *env)
325b9c5d822SKumar Kartikeya Dwivedi {
326b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
327b9c5d822SKumar Kartikeya Dwivedi 
328b9c5d822SKumar Kartikeya Dwivedi 	if (!diag)
329b9c5d822SKumar Kartikeya Dwivedi 		return;
330b9c5d822SKumar Kartikeya Dwivedi 
331b9c5d822SKumar Kartikeya Dwivedi 	diag_fmt_restore(env, (struct diag_fmt_mark){});
332daf82487SKumar Kartikeya Dwivedi 	kvfree(diag->log.events);
333b9c5d822SKumar Kartikeya Dwivedi 	kfree(diag);
334b9c5d822SKumar Kartikeya Dwivedi 	env->diag = NULL;
335b9c5d822SKumar Kartikeya Dwivedi }
336b9c5d822SKumar Kartikeya Dwivedi 
3375ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...)
3385ad74616SKumar Kartikeya Dwivedi {
3395ad74616SKumar Kartikeya Dwivedi 	va_list args;
3405ad74616SKumar Kartikeya Dwivedi 
3415ad74616SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
3425ad74616SKumar Kartikeya Dwivedi 		return;
3435ad74616SKumar Kartikeya Dwivedi 
3445ad74616SKumar Kartikeya Dwivedi 	va_start(args, fmt);
3455ad74616SKumar Kartikeya Dwivedi 	bpf_verifier_vlog(&env->log, fmt, args);
3465ad74616SKumar Kartikeya Dwivedi 	va_end(args);
3475ad74616SKumar Kartikeya Dwivedi }
3485ad74616SKumar Kartikeya Dwivedi 
349daf82487SKumar Kartikeya Dwivedi static u64 log_end(const struct bpf_diag_log *log)
350daf82487SKumar Kartikeya Dwivedi {
351daf82487SKumar Kartikeya Dwivedi 	return log->first_seq + log->cnt;
352daf82487SKumar Kartikeya Dwivedi }
353daf82487SKumar Kartikeya Dwivedi 
354daf82487SKumar Kartikeya Dwivedi static u32 log_pos(const struct bpf_diag_log *log, u32 idx)
355daf82487SKumar Kartikeya Dwivedi {
356daf82487SKumar Kartikeya Dwivedi 	u32 pos = log->head + idx;
357daf82487SKumar Kartikeya Dwivedi 
358daf82487SKumar Kartikeya Dwivedi 	return pos < log->cap ? pos : pos - log->cap;
359daf82487SKumar Kartikeya Dwivedi }
360daf82487SKumar Kartikeya Dwivedi 
361daf82487SKumar Kartikeya Dwivedi u64 bpf_diag_event_log_save(struct bpf_verifier_env *env)
362daf82487SKumar Kartikeya Dwivedi {
363daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
364daf82487SKumar Kartikeya Dwivedi 
365daf82487SKumar Kartikeya Dwivedi 	return diag ? log_end(&diag->log) : 0;
366daf82487SKumar Kartikeya Dwivedi }
367daf82487SKumar Kartikeya Dwivedi 
368daf82487SKumar Kartikeya Dwivedi void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos)
369daf82487SKumar Kartikeya Dwivedi {
370daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
371daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log *log;
372daf82487SKumar Kartikeya Dwivedi 	u64 end_seq;
373daf82487SKumar Kartikeya Dwivedi 
374daf82487SKumar Kartikeya Dwivedi 	if (!diag)
375daf82487SKumar Kartikeya Dwivedi 		return;
376daf82487SKumar Kartikeya Dwivedi 
377daf82487SKumar Kartikeya Dwivedi 	log = &diag->log;
378daf82487SKumar Kartikeya Dwivedi 	end_seq = log_end(log);
379daf82487SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(log_pos > end_seq))
380daf82487SKumar Kartikeya Dwivedi 		log_pos = end_seq;
381daf82487SKumar Kartikeya Dwivedi 
382daf82487SKumar Kartikeya Dwivedi 	/*
383daf82487SKumar Kartikeya Dwivedi 	 * A deep abandoned path may have rotated away the shared prefix. In
384daf82487SKumar Kartikeya Dwivedi 	 * that case, restart with an empty retained suffix and remember that
385daf82487SKumar Kartikeya Dwivedi 	 * every event before the restored mark is unavailable.
386daf82487SKumar Kartikeya Dwivedi 	 */
387daf82487SKumar Kartikeya Dwivedi 	if (log_pos <= log->first_seq) {
388daf82487SKumar Kartikeya Dwivedi 		log->first_seq = log_pos;
389daf82487SKumar Kartikeya Dwivedi 		log->head = 0;
390daf82487SKumar Kartikeya Dwivedi 		log->cnt = 0;
391daf82487SKumar Kartikeya Dwivedi 		return;
392daf82487SKumar Kartikeya Dwivedi 	}
393daf82487SKumar Kartikeya Dwivedi 
394daf82487SKumar Kartikeya Dwivedi 	log->cnt = log_pos - log->first_seq;
395daf82487SKumar Kartikeya Dwivedi }
396daf82487SKumar Kartikeya Dwivedi 
397*956a66e5SKumar Kartikeya Dwivedi u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state)
398*956a66e5SKumar Kartikeya Dwivedi {
399*956a66e5SKumar Kartikeya Dwivedi 	u32 depth = 0;
400*956a66e5SKumar Kartikeya Dwivedi 	int i;
401*956a66e5SKumar Kartikeya Dwivedi 
402*956a66e5SKumar Kartikeya Dwivedi 	for (i = 0; i < state->acquired_refs; i++) {
403*956a66e5SKumar Kartikeya Dwivedi 		if (state->refs[i].type == REF_TYPE_IRQ)
404*956a66e5SKumar Kartikeya Dwivedi 			depth++;
405*956a66e5SKumar Kartikeya Dwivedi 	}
406*956a66e5SKumar Kartikeya Dwivedi 
407*956a66e5SKumar Kartikeya Dwivedi 	return depth;
408*956a66e5SKumar Kartikeya Dwivedi }
409*956a66e5SKumar Kartikeya Dwivedi 
410daf82487SKumar Kartikeya Dwivedi static void diag_append_history(struct bpf_verifier_env *env,
411daf82487SKumar Kartikeya Dwivedi 				const struct bpf_diag_history_event *event)
412daf82487SKumar Kartikeya Dwivedi {
413daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event *events;
414daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
415daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_log *log;
416daf82487SKumar Kartikeya Dwivedi 	u32 cap, max_events;
417daf82487SKumar Kartikeya Dwivedi 
418daf82487SKumar Kartikeya Dwivedi 	if (!diag)
419daf82487SKumar Kartikeya Dwivedi 		return;
420daf82487SKumar Kartikeya Dwivedi 	log = &diag->log;
421daf82487SKumar Kartikeya Dwivedi 
422daf82487SKumar Kartikeya Dwivedi 	if (log->cnt < log->cap) {
423daf82487SKumar Kartikeya Dwivedi 		log->events[log_pos(log, log->cnt++)] = *event;
424daf82487SKumar Kartikeya Dwivedi 		return;
425daf82487SKumar Kartikeya Dwivedi 	}
426daf82487SKumar Kartikeya Dwivedi 
427daf82487SKumar Kartikeya Dwivedi 	max_events = BPF_DIAG_EVENT_LOG_MAX_SIZE / sizeof(*events);
428daf82487SKumar Kartikeya Dwivedi 	if (log->growth_failed || log->cap == max_events)
429daf82487SKumar Kartikeya Dwivedi 		goto rotate;
430daf82487SKumar Kartikeya Dwivedi 
431daf82487SKumar Kartikeya Dwivedi 	cap = min(log->cap ? log->cap * 2 : 64, max_events);
432daf82487SKumar Kartikeya Dwivedi 	events = kvrealloc(log->events, array_size(cap, sizeof(*events)), GFP_KERNEL_ACCOUNT);
433daf82487SKumar Kartikeya Dwivedi 	if (!events) {
434daf82487SKumar Kartikeya Dwivedi 		log->growth_failed = true;
435daf82487SKumar Kartikeya Dwivedi 		goto rotate;
436daf82487SKumar Kartikeya Dwivedi 	}
437daf82487SKumar Kartikeya Dwivedi 	log->events = events;
438daf82487SKumar Kartikeya Dwivedi 	log->cap = cap;
439daf82487SKumar Kartikeya Dwivedi 	log->events[log->cnt++] = *event;
440daf82487SKumar Kartikeya Dwivedi 	return;
441daf82487SKumar Kartikeya Dwivedi 
442daf82487SKumar Kartikeya Dwivedi rotate:
443daf82487SKumar Kartikeya Dwivedi 	if (log->cap) {
444daf82487SKumar Kartikeya Dwivedi 		log->events[log->head++] = *event;
445daf82487SKumar Kartikeya Dwivedi 		if (log->head == log->cap)
446daf82487SKumar Kartikeya Dwivedi 			log->head = 0;
447daf82487SKumar Kartikeya Dwivedi 	}
448daf82487SKumar Kartikeya Dwivedi 	log->first_seq++;
449daf82487SKumar Kartikeya Dwivedi }
450daf82487SKumar Kartikeya Dwivedi 
451b9c5d822SKumar Kartikeya Dwivedi static void diag_print_wrapped_prefixed(struct bpf_verifier_env *env, const char *first_prefix,
452b9c5d822SKumar Kartikeya Dwivedi 					const char *next_prefix, const char *text)
453b9c5d822SKumar Kartikeya Dwivedi {
454b9c5d822SKumar Kartikeya Dwivedi 	const char *prefix = first_prefix;
455b9c5d822SKumar Kartikeya Dwivedi 
456b9c5d822SKumar Kartikeya Dwivedi 	while (*text) {
457b9c5d822SKumar Kartikeya Dwivedi 		const char *line = text;
458b9c5d822SKumar Kartikeya Dwivedi 		int prefix_len = strlen(prefix);
459b9c5d822SKumar Kartikeya Dwivedi 		int text_width = BPF_DIAG_TEXT_WIDTH - prefix_len;
460b9c5d822SKumar Kartikeya Dwivedi 		int len = 0, last_space = -1;
461b9c5d822SKumar Kartikeya Dwivedi 
462b9c5d822SKumar Kartikeya Dwivedi 		if (text_width < 1)
463b9c5d822SKumar Kartikeya Dwivedi 			text_width = 1;
464b9c5d822SKumar Kartikeya Dwivedi 
465b9c5d822SKumar Kartikeya Dwivedi 		while (line[len] && line[len] != '\n' && len < text_width) {
466b9c5d822SKumar Kartikeya Dwivedi 			if (line[len] == ' ')
467b9c5d822SKumar Kartikeya Dwivedi 				last_space = len;
468b9c5d822SKumar Kartikeya Dwivedi 			len++;
469b9c5d822SKumar Kartikeya Dwivedi 		}
470b9c5d822SKumar Kartikeya Dwivedi 
471b9c5d822SKumar Kartikeya Dwivedi 		if (line[len] && line[len] != '\n' && line[len] != ' ' && last_space > 0)
472b9c5d822SKumar Kartikeya Dwivedi 			len = last_space;
473b9c5d822SKumar Kartikeya Dwivedi 
474b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "%s%.*s\n", prefix, len, line);
475b9c5d822SKumar Kartikeya Dwivedi 
476b9c5d822SKumar Kartikeya Dwivedi 		text = line + len;
477b9c5d822SKumar Kartikeya Dwivedi 		while (*text == ' ')
478b9c5d822SKumar Kartikeya Dwivedi 			text++;
479b9c5d822SKumar Kartikeya Dwivedi 		if (*text == '\n')
480b9c5d822SKumar Kartikeya Dwivedi 			text++;
481b9c5d822SKumar Kartikeya Dwivedi 
482b9c5d822SKumar Kartikeya Dwivedi 		prefix = next_prefix;
483b9c5d822SKumar Kartikeya Dwivedi 	}
484b9c5d822SKumar Kartikeya Dwivedi }
485b9c5d822SKumar Kartikeya Dwivedi 
486af4ea6e2SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id)
487af4ea6e2SKumar Kartikeya Dwivedi {
488af4ea6e2SKumar Kartikeya Dwivedi 	char *buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE);
489af4ea6e2SKumar Kartikeya Dwivedi 	size_t len;
490af4ea6e2SKumar Kartikeya Dwivedi 	int ret;
491af4ea6e2SKumar Kartikeya Dwivedi 
492af4ea6e2SKumar Kartikeya Dwivedi 	if (!buf)
493af4ea6e2SKumar Kartikeya Dwivedi 		return "";
494af4ea6e2SKumar Kartikeya Dwivedi 
495af4ea6e2SKumar Kartikeya Dwivedi 	buf[0] = '\0';
496af4ea6e2SKumar Kartikeya Dwivedi 	ret = btf_type_name_to_buf(btf, type_id, buf, BPF_DIAG_FMT_BUF_SIZE);
497af4ea6e2SKumar Kartikeya Dwivedi 	if (ret < 0 || !buf[0]) {
498af4ea6e2SKumar Kartikeya Dwivedi 		scnprintf(buf, BPF_DIAG_FMT_BUF_SIZE, "BTF type ID %u", type_id);
499af4ea6e2SKumar Kartikeya Dwivedi 		return buf;
500af4ea6e2SKumar Kartikeya Dwivedi 	}
501af4ea6e2SKumar Kartikeya Dwivedi 
502af4ea6e2SKumar Kartikeya Dwivedi 	len = strlen(buf);
503af4ea6e2SKumar Kartikeya Dwivedi 	if (len && buf[len - 1] == '{')
504af4ea6e2SKumar Kartikeya Dwivedi 		buf[len - 1] = '\0';
505af4ea6e2SKumar Kartikeya Dwivedi 	return buf;
506af4ea6e2SKumar Kartikeya Dwivedi }
507af4ea6e2SKumar Kartikeya Dwivedi 
508b9c5d822SKumar Kartikeya Dwivedi static int diag_line_width(unsigned int line)
509b9c5d822SKumar Kartikeya Dwivedi {
510b9c5d822SKumar Kartikeya Dwivedi 	int width = 1;
511b9c5d822SKumar Kartikeya Dwivedi 
512b9c5d822SKumar Kartikeya Dwivedi 	while (line >= 10) {
513b9c5d822SKumar Kartikeya Dwivedi 		line /= 10;
514b9c5d822SKumar Kartikeya Dwivedi 		width++;
515b9c5d822SKumar Kartikeya Dwivedi 	}
516b9c5d822SKumar Kartikeya Dwivedi 
517b9c5d822SKumar Kartikeya Dwivedi 	return width;
518b9c5d822SKumar Kartikeya Dwivedi }
519b9c5d822SKumar Kartikeya Dwivedi 
520b9c5d822SKumar Kartikeya Dwivedi static int diag_line_indent(const char *line)
521b9c5d822SKumar Kartikeya Dwivedi {
522b9c5d822SKumar Kartikeya Dwivedi 	int indent = 0;
523b9c5d822SKumar Kartikeya Dwivedi 
524b9c5d822SKumar Kartikeya Dwivedi 	while (*line == ' ' || *line == '\t') {
525b9c5d822SKumar Kartikeya Dwivedi 		if (*line == '\t')
526b9c5d822SKumar Kartikeya Dwivedi 			indent = round_up(indent + 1, BPF_DIAG_TAB_WIDTH);
527b9c5d822SKumar Kartikeya Dwivedi 		else
528b9c5d822SKumar Kartikeya Dwivedi 			indent++;
529b9c5d822SKumar Kartikeya Dwivedi 		line++;
530b9c5d822SKumar Kartikeya Dwivedi 	}
531b9c5d822SKumar Kartikeya Dwivedi 
532b9c5d822SKumar Kartikeya Dwivedi 	return indent;
533b9c5d822SKumar Kartikeya Dwivedi }
534b9c5d822SKumar Kartikeya Dwivedi 
535b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) __printf(2, 3);
536b9c5d822SKumar Kartikeya Dwivedi 
537b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...)
538b9c5d822SKumar Kartikeya Dwivedi {
539b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx *ctx = private_data;
540b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
541b9c5d822SKumar Kartikeya Dwivedi 
542b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
543b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_vprintf(&ctx->seq, fmt, args);
544b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
545b9c5d822SKumar Kartikeya Dwivedi }
546b9c5d822SKumar Kartikeya Dwivedi 
547b9c5d822SKumar Kartikeya Dwivedi static const char *disasm_kfunc_name(void *private_data, const struct bpf_insn *insn)
548b9c5d822SKumar Kartikeya Dwivedi {
549b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx *ctx = private_data;
550b9c5d822SKumar Kartikeya Dwivedi 
551b9c5d822SKumar Kartikeya Dwivedi 	return bpf_disasm_kfunc_name(ctx->env, insn);
552b9c5d822SKumar Kartikeya Dwivedi }
553b9c5d822SKumar Kartikeya Dwivedi 
554b9c5d822SKumar Kartikeya Dwivedi static void format_disasm_line(struct bpf_verifier_env *env, int insn_idx,
555b9c5d822SKumar Kartikeya Dwivedi 			       struct disasm_line *line)
556b9c5d822SKumar Kartikeya Dwivedi {
557b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_ctx ctx = { .env = env };
558b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_insn *insn;
559b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_insn_cbs cbs = {
560b9c5d822SKumar Kartikeya Dwivedi 		.cb_call = disasm_kfunc_name,
561b9c5d822SKumar Kartikeya Dwivedi 		.cb_print = disasm_print,
562b9c5d822SKumar Kartikeya Dwivedi 		.private_data = &ctx,
563b9c5d822SKumar Kartikeya Dwivedi 	};
564b9c5d822SKumar Kartikeya Dwivedi 
565b9c5d822SKumar Kartikeya Dwivedi 	line->idx = insn_idx;
566b9c5d822SKumar Kartikeya Dwivedi 	line->valid = false;
567b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_init(&ctx.seq, line->text, sizeof(line->text));
568b9c5d822SKumar Kartikeya Dwivedi 
569b9c5d822SKumar Kartikeya Dwivedi 	if (insn_idx < 0 || insn_idx >= env->prog->len)
570b9c5d822SKumar Kartikeya Dwivedi 		return;
571b9c5d822SKumar Kartikeya Dwivedi 
572b9c5d822SKumar Kartikeya Dwivedi 	if (insn_idx > 0 && bpf_is_ldimm64(&env->prog->insnsi[insn_idx - 1]))
573b9c5d822SKumar Kartikeya Dwivedi 		return;
574b9c5d822SKumar Kartikeya Dwivedi 
575b9c5d822SKumar Kartikeya Dwivedi 	insn = &env->prog->insnsi[insn_idx];
576b9c5d822SKumar Kartikeya Dwivedi 	if (bpf_is_ldimm64(insn) && insn_idx + 1 >= env->prog->len)
577b9c5d822SKumar Kartikeya Dwivedi 		return;
578b9c5d822SKumar Kartikeya Dwivedi 
579b9c5d822SKumar Kartikeya Dwivedi 	print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
580b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_str(&ctx.seq);
581b9c5d822SKumar Kartikeya Dwivedi 	ctx.seq.len = strnlen(line->text, sizeof(line->text));
582b9c5d822SKumar Kartikeya Dwivedi 	while (ctx.seq.len && line->text[ctx.seq.len - 1] == '\n')
583b9c5d822SKumar Kartikeya Dwivedi 		seq_buf_pop(&ctx.seq);
584b9c5d822SKumar Kartikeya Dwivedi 	seq_buf_str(&ctx.seq);
585b9c5d822SKumar Kartikeya Dwivedi 
586b9c5d822SKumar Kartikeya Dwivedi 	line->valid = true;
587b9c5d822SKumar Kartikeya Dwivedi }
588b9c5d822SKumar Kartikeya Dwivedi 
589b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_text(char *buf, size_t size, const char *line, int width)
590b9c5d822SKumar Kartikeya Dwivedi {
591b9c5d822SKumar Kartikeya Dwivedi 	int col = 0, len = 0;
592b9c5d822SKumar Kartikeya Dwivedi 
593b9c5d822SKumar Kartikeya Dwivedi 	if (!size)
594b9c5d822SKumar Kartikeya Dwivedi 		return;
595b9c5d822SKumar Kartikeya Dwivedi 	if (width <= 0) {
596b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
597b9c5d822SKumar Kartikeya Dwivedi 		return;
598b9c5d822SKumar Kartikeya Dwivedi 	}
599b9c5d822SKumar Kartikeya Dwivedi 
600b9c5d822SKumar Kartikeya Dwivedi 	line = line ?: "...";
601b9c5d822SKumar Kartikeya Dwivedi 	while (*line && col < width && len + 1 < size) {
602b9c5d822SKumar Kartikeya Dwivedi 		if (*line == '\t') {
603b9c5d822SKumar Kartikeya Dwivedi 			int next = round_up(col + 1, BPF_DIAG_TAB_WIDTH);
604b9c5d822SKumar Kartikeya Dwivedi 
605b9c5d822SKumar Kartikeya Dwivedi 			while (col < next && col < width && len + 1 < size) {
606b9c5d822SKumar Kartikeya Dwivedi 				buf[len++] = ' ';
607b9c5d822SKumar Kartikeya Dwivedi 				col++;
608b9c5d822SKumar Kartikeya Dwivedi 			}
609b9c5d822SKumar Kartikeya Dwivedi 			line++;
610b9c5d822SKumar Kartikeya Dwivedi 			continue;
611b9c5d822SKumar Kartikeya Dwivedi 		}
612b9c5d822SKumar Kartikeya Dwivedi 
613b9c5d822SKumar Kartikeya Dwivedi 		buf[len++] = *line++;
614b9c5d822SKumar Kartikeya Dwivedi 		col++;
615b9c5d822SKumar Kartikeya Dwivedi 	}
616b9c5d822SKumar Kartikeya Dwivedi 
617b9c5d822SKumar Kartikeya Dwivedi 	if (*line) {
618b9c5d822SKumar Kartikeya Dwivedi 		int ellipsis_len = min(3, width);
619b9c5d822SKumar Kartikeya Dwivedi 
620b9c5d822SKumar Kartikeya Dwivedi 		while (len > 0 && col > width - ellipsis_len) {
621b9c5d822SKumar Kartikeya Dwivedi 			len--;
622b9c5d822SKumar Kartikeya Dwivedi 			col--;
623b9c5d822SKumar Kartikeya Dwivedi 		}
624b9c5d822SKumar Kartikeya Dwivedi 		while (ellipsis_len-- && len + 1 < size)
625b9c5d822SKumar Kartikeya Dwivedi 			buf[len++] = '.';
626b9c5d822SKumar Kartikeya Dwivedi 	}
627b9c5d822SKumar Kartikeya Dwivedi 
628b9c5d822SKumar Kartikeya Dwivedi 	buf[len] = '\0';
629b9c5d822SKumar Kartikeya Dwivedi }
630b9c5d822SKumar Kartikeya Dwivedi 
631b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_lane(char *buf, size_t size, const char *source_prefix,
632b9c5d822SKumar Kartikeya Dwivedi 				    int source_line_width, int line_num, const char *line)
633b9c5d822SKumar Kartikeya Dwivedi {
634b9c5d822SKumar Kartikeya Dwivedi 	int len, text_width;
635b9c5d822SKumar Kartikeya Dwivedi 
636b9c5d822SKumar Kartikeya Dwivedi 	if (line_num <= 0) {
637b9c5d822SKumar Kartikeya Dwivedi 		buf[0] = '\0';
638b9c5d822SKumar Kartikeya Dwivedi 		return;
639b9c5d822SKumar Kartikeya Dwivedi 	}
640b9c5d822SKumar Kartikeya Dwivedi 
641b9c5d822SKumar Kartikeya Dwivedi 	len = scnprintf(buf, size, "%s%*d | ", source_prefix, source_line_width, line_num);
642b9c5d822SKumar Kartikeya Dwivedi 	text_width = BPF_DIAG_SOURCE_LANE_WIDTH - len;
643b9c5d822SKumar Kartikeya Dwivedi 	diag_format_source_text(buf + len, size - len, line, text_width);
644b9c5d822SKumar Kartikeya Dwivedi }
645b9c5d822SKumar Kartikeya Dwivedi 
6465ad74616SKumar Kartikeya Dwivedi static void bpf_diag_header(struct bpf_verifier_env *env, const char *category,
6475ad74616SKumar Kartikeya Dwivedi 			    const char *problem)
6485ad74616SKumar Kartikeya Dwivedi {
6495ad74616SKumar Kartikeya Dwivedi 	char first;
6505ad74616SKumar Kartikeya Dwivedi 
6515ad74616SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
6525ad74616SKumar Kartikeya Dwivedi 		return;
6535ad74616SKumar Kartikeya Dwivedi 
6545ad74616SKumar Kartikeya Dwivedi 	category = category ?: "Verifier Error";
6555ad74616SKumar Kartikeya Dwivedi 	problem = problem ?: "";
6565ad74616SKumar Kartikeya Dwivedi 
6575ad74616SKumar Kartikeya Dwivedi 	if (!problem[0]) {
6585ad74616SKumar Kartikeya Dwivedi 		diag_write(env, "\nVerification failed: %s\n", category);
6595ad74616SKumar Kartikeya Dwivedi 		return;
6605ad74616SKumar Kartikeya Dwivedi 	}
6615ad74616SKumar Kartikeya Dwivedi 
6625ad74616SKumar Kartikeya Dwivedi 	first = toupper(problem[0]);
6635ad74616SKumar Kartikeya Dwivedi 	diag_write(env, "\nVerification failed: %s: %c%s\n", category, first, problem + 1);
6645ad74616SKumar Kartikeya Dwivedi }
665b9c5d822SKumar Kartikeya Dwivedi 
666b9c5d822SKumar Kartikeya Dwivedi static void diag_print_source_annotation(struct bpf_verifier_env *env, int line_width, int indent,
667b9c5d822SKumar Kartikeya Dwivedi 					 const char *label, const char *msg)
668b9c5d822SKumar Kartikeya Dwivedi {
669b9c5d822SKumar Kartikeya Dwivedi 	const char *first_prefix, *next_prefix, *text;
670b9c5d822SKumar Kartikeya Dwivedi 
671b9c5d822SKumar Kartikeya Dwivedi 	indent = min_t(int, indent, max_t(int, 0, BPF_DIAG_SOURCE_LANE_WIDTH - line_width - 8));
672b9c5d822SKumar Kartikeya Dwivedi 	text = bpf_diag_fmt(env, "%s: %s", label, msg);
673b9c5d822SKumar Kartikeya Dwivedi 	first_prefix = bpf_diag_fmt(env, "  %*s | %*s^-- ", line_width + 4, "", indent, "");
674b9c5d822SKumar Kartikeya Dwivedi 	next_prefix = bpf_diag_fmt(env, "  %*s | %*s    ", line_width + 4, "", indent, "");
675b9c5d822SKumar Kartikeya Dwivedi 
676b9c5d822SKumar Kartikeya Dwivedi 	diag_print_wrapped_prefixed(env, first_prefix, next_prefix, text);
677b9c5d822SKumar Kartikeya Dwivedi }
678b9c5d822SKumar Kartikeya Dwivedi 
679b9c5d822SKumar Kartikeya Dwivedi static void diag_print_insn_context(struct bpf_verifier_env *env, u32 insn_idx,
680b9c5d822SKumar Kartikeya Dwivedi 				    struct disasm_line *disasm_lines)
681b9c5d822SKumar Kartikeya Dwivedi {
682b9c5d822SKumar Kartikeya Dwivedi 	int insn_width = diag_line_width(env->prog->len ? env->prog->len - 1 : 0);
683b9c5d822SKumar Kartikeya Dwivedi 	int i;
684b9c5d822SKumar Kartikeya Dwivedi 
685b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
686b9c5d822SKumar Kartikeya Dwivedi 		int row = i - BPF_DIAG_CONTEXT;
687b9c5d822SKumar Kartikeya Dwivedi 
688b9c5d822SKumar Kartikeya Dwivedi 		format_disasm_line(env, insn_idx + row, &disasm_lines[i]);
689b9c5d822SKumar Kartikeya Dwivedi 	}
690b9c5d822SKumar Kartikeya Dwivedi 
691b9c5d822SKumar Kartikeya Dwivedi 	diag_write(env, "  Instruction context:\n");
692b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
693b9c5d822SKumar Kartikeya Dwivedi 		struct disasm_line *line = &disasm_lines[i];
694b9c5d822SKumar Kartikeya Dwivedi 
695b9c5d822SKumar Kartikeya Dwivedi 		if (line->valid)
696b9c5d822SKumar Kartikeya Dwivedi 			diag_write(env, "  %s%*d | %s\n",
697b9c5d822SKumar Kartikeya Dwivedi 				   line->idx == insn_idx ? ">>> " : "    ",
698b9c5d822SKumar Kartikeya Dwivedi 				   insn_width, line->idx, line->text);
699b9c5d822SKumar Kartikeya Dwivedi 	}
700b9c5d822SKumar Kartikeya Dwivedi }
701b9c5d822SKumar Kartikeya Dwivedi 
702b9c5d822SKumar Kartikeya Dwivedi static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label,
703b9c5d822SKumar Kartikeya Dwivedi 			    const char *fmt, ...)
704b9c5d822SKumar Kartikeya Dwivedi {
705b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_diag_scratch *scratch;
706b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source *source_lines;
707b9c5d822SKumar Kartikeya Dwivedi 	struct disasm_line *disasm_lines;
708b9c5d822SKumar Kartikeya Dwivedi 	struct bpf_linfo_source src = {};
709b9c5d822SKumar Kartikeya Dwivedi 	struct diag_fmt_mark mark;
710b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_line_info *linfo;
711b9c5d822SKumar Kartikeya Dwivedi 	const struct bpf_subprog_info *subprog;
712b9c5d822SKumar Kartikeya Dwivedi 	struct btf *btf = env->prog->aux->btf;
713b9c5d822SKumar Kartikeya Dwivedi 	char *source_lane;
714b9c5d822SKumar Kartikeya Dwivedi 	const char *msg;
715b9c5d822SKumar Kartikeya Dwivedi 	const char *func;
716b9c5d822SKumar Kartikeya Dwivedi 	int start_line, end_line, width, indent, subprogno, linfo_start, linfo_end, i;
717b9c5d822SKumar Kartikeya Dwivedi 	va_list args;
718b9c5d822SKumar Kartikeya Dwivedi 
719b9c5d822SKumar Kartikeya Dwivedi 	if (!bpf_diag_enabled(env))
720b9c5d822SKumar Kartikeya Dwivedi 		return;
721b9c5d822SKumar Kartikeya Dwivedi 	if (!env->diag)
722b9c5d822SKumar Kartikeya Dwivedi 		return;
723b9c5d822SKumar Kartikeya Dwivedi 
724b9c5d822SKumar Kartikeya Dwivedi 	mark = diag_fmt_save(env);
725b9c5d822SKumar Kartikeya Dwivedi 	label = label ?: "note";
726b9c5d822SKumar Kartikeya Dwivedi 	scratch = &env->diag->scratch;
727b9c5d822SKumar Kartikeya Dwivedi 	source_lines = scratch->source_lines;
728b9c5d822SKumar Kartikeya Dwivedi 	disasm_lines = scratch->disasm_lines;
729b9c5d822SKumar Kartikeya Dwivedi 	memset(source_lines, 0, sizeof(scratch->source_lines));
730b9c5d822SKumar Kartikeya Dwivedi 	memset(disasm_lines, 0, sizeof(scratch->disasm_lines));
731b9c5d822SKumar Kartikeya Dwivedi 
732b9c5d822SKumar Kartikeya Dwivedi 	va_start(args, fmt);
733b9c5d822SKumar Kartikeya Dwivedi 	msg = bpf_diag_vfmt(env, fmt, args);
734b9c5d822SKumar Kartikeya Dwivedi 	va_end(args);
735b9c5d822SKumar Kartikeya Dwivedi 	if (!*msg)
736b9c5d822SKumar Kartikeya Dwivedi 		msg = "<failed to allocate diagnostic text>";
737b9c5d822SKumar Kartikeya Dwivedi 
738b9c5d822SKumar Kartikeya Dwivedi 	linfo = bpf_find_linfo(env->prog, insn_idx);
739b9c5d822SKumar Kartikeya Dwivedi 	if (btf && linfo)
740b9c5d822SKumar Kartikeya Dwivedi 		bpf_get_linfo_source(btf, linfo, &src);
741b9c5d822SKumar Kartikeya Dwivedi 	if (!src.file || !*src.file || !src.line || !*src.line) {
742b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  insn %u\n", insn_idx);
743b9c5d822SKumar Kartikeya Dwivedi 		diag_print_source_annotation(env, 0, 0, label, msg);
744b9c5d822SKumar Kartikeya Dwivedi 		diag_print_insn_context(env, insn_idx, disasm_lines);
745b9c5d822SKumar Kartikeya Dwivedi 		goto out_restore;
746b9c5d822SKumar Kartikeya Dwivedi 	}
747b9c5d822SKumar Kartikeya Dwivedi 
748b9c5d822SKumar Kartikeya Dwivedi 	subprog = bpf_find_containing_subprog(env, insn_idx);
749b9c5d822SKumar Kartikeya Dwivedi 	subprogno = subprog ? subprog - env->subprog_info : -ENOENT;
750b9c5d822SKumar Kartikeya Dwivedi 	func = subprogno >= 0 ? bpf_subprog_name(env, subprogno) : NULL;
751b9c5d822SKumar Kartikeya Dwivedi 	if (func && *func)
752b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s @ %s:%d:%d\n", func, src.file, src.line_num, src.line_col);
753b9c5d822SKumar Kartikeya Dwivedi 	else
754b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s:%d:%d\n", src.file, src.line_num, src.line_col);
755b9c5d822SKumar Kartikeya Dwivedi 
756b9c5d822SKumar Kartikeya Dwivedi 	start_line = src.line_num - BPF_DIAG_CONTEXT;
757b9c5d822SKumar Kartikeya Dwivedi 	end_line = src.line_num + BPF_DIAG_CONTEXT;
758b9c5d822SKumar Kartikeya Dwivedi 	width = diag_line_width(end_line);
759b9c5d822SKumar Kartikeya Dwivedi 	indent = diag_line_indent(src.line);
760b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++)
761b9c5d822SKumar Kartikeya Dwivedi 		source_lines[i].line_num = start_line + i;
762b9c5d822SKumar Kartikeya Dwivedi 
763b9c5d822SKumar Kartikeya Dwivedi 	linfo = env->prog->aux->linfo;
764b9c5d822SKumar Kartikeya Dwivedi 	linfo_start = subprog ? subprog->linfo_idx : 0;
765b9c5d822SKumar Kartikeya Dwivedi 	linfo_end = subprogno >= 0 && subprogno + 1 < env->subprog_cnt ?
766b9c5d822SKumar Kartikeya Dwivedi 		    env->subprog_info[subprogno + 1].linfo_idx : env->prog->aux->nr_linfo;
767b9c5d822SKumar Kartikeya Dwivedi 	for (i = linfo_start; i < linfo_end; i++) {
768b9c5d822SKumar Kartikeya Dwivedi 		struct bpf_linfo_source line_src;
769b9c5d822SKumar Kartikeya Dwivedi 		int idx;
770b9c5d822SKumar Kartikeya Dwivedi 
771b9c5d822SKumar Kartikeya Dwivedi 		bpf_get_linfo_source(btf, &linfo[i], &line_src);
772b9c5d822SKumar Kartikeya Dwivedi 		if (line_src.file_name_off != src.file_name_off ||
773b9c5d822SKumar Kartikeya Dwivedi 		    line_src.line_num < start_line || line_src.line_num > end_line ||
774b9c5d822SKumar Kartikeya Dwivedi 		    !line_src.line || !*line_src.line)
775b9c5d822SKumar Kartikeya Dwivedi 			continue;
776b9c5d822SKumar Kartikeya Dwivedi 
777b9c5d822SKumar Kartikeya Dwivedi 		idx = line_src.line_num - start_line;
778b9c5d822SKumar Kartikeya Dwivedi 		if (!source_lines[idx].line)
779b9c5d822SKumar Kartikeya Dwivedi 			source_lines[idx] = line_src;
780b9c5d822SKumar Kartikeya Dwivedi 	}
781b9c5d822SKumar Kartikeya Dwivedi 
782b9c5d822SKumar Kartikeya Dwivedi 	diag_write(env, "  Source context:\n");
783b9c5d822SKumar Kartikeya Dwivedi 	source_lane = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE);
784b9c5d822SKumar Kartikeya Dwivedi 	if (!source_lane)
785b9c5d822SKumar Kartikeya Dwivedi 		goto out_restore;
786b9c5d822SKumar Kartikeya Dwivedi 	for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) {
787b9c5d822SKumar Kartikeya Dwivedi 		const char *source_prefix;
788b9c5d822SKumar Kartikeya Dwivedi 
789b9c5d822SKumar Kartikeya Dwivedi 		source_prefix = source_lines[i].line_num == src.line_num ? ">>> " : "    ";
790b9c5d822SKumar Kartikeya Dwivedi 		diag_format_source_lane(source_lane, BPF_DIAG_FMT_BUF_SIZE, source_prefix, width,
791b9c5d822SKumar Kartikeya Dwivedi 					source_lines[i].line_num, source_lines[i].line);
792b9c5d822SKumar Kartikeya Dwivedi 		diag_write(env, "  %s\n", source_lane);
793b9c5d822SKumar Kartikeya Dwivedi 		if (source_lines[i].line_num == src.line_num)
794b9c5d822SKumar Kartikeya Dwivedi 			diag_print_source_annotation(env, width, indent, label, msg);
795b9c5d822SKumar Kartikeya Dwivedi 	}
796b9c5d822SKumar Kartikeya Dwivedi 	diag_print_insn_context(env, insn_idx, disasm_lines);
797b9c5d822SKumar Kartikeya Dwivedi 
798b9c5d822SKumar Kartikeya Dwivedi out_restore:
799b9c5d822SKumar Kartikeya Dwivedi 	diag_fmt_restore(env, mark);
800b9c5d822SKumar Kartikeya Dwivedi }
801daf82487SKumar Kartikeya Dwivedi 
802daf82487SKumar Kartikeya Dwivedi void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true)
803daf82487SKumar Kartikeya Dwivedi {
804daf82487SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
805daf82487SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
806daf82487SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_BRANCH,
807daf82487SKumar Kartikeya Dwivedi 		.branch = {
808daf82487SKumar Kartikeya Dwivedi 			.cond_true = cond_true,
809daf82487SKumar Kartikeya Dwivedi 		},
810daf82487SKumar Kartikeya Dwivedi 	};
811daf82487SKumar Kartikeya Dwivedi 
812daf82487SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
813daf82487SKumar Kartikeya Dwivedi }
814af4ea6e2SKumar Kartikeya Dwivedi 
815af4ea6e2SKumar Kartikeya Dwivedi static void diag_snapshot_reg(struct bpf_diag_reg_snapshot *snapshot,
816af4ea6e2SKumar Kartikeya Dwivedi 			      const struct bpf_reg_state *reg)
817af4ea6e2SKumar Kartikeya Dwivedi {
818af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->type = reg->type;
819af4ea6e2SKumar Kartikeya Dwivedi 	if (type_is_map_ptr(reg->type))
820af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->map_ptr = reg->map_ptr;
821af4ea6e2SKumar Kartikeya Dwivedi 	if (base_type(reg->type) == PTR_TO_BTF_ID && reg->btf && reg->btf_id) {
822af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->btf_id = reg->btf_id;
823af4ea6e2SKumar Kartikeya Dwivedi 		snapshot->btf = reg->btf;
824af4ea6e2SKumar Kartikeya Dwivedi 	}
825af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->var_off = reg->var_off;
826af4ea6e2SKumar Kartikeya Dwivedi 	snapshot->r64 = reg->r64;
827af4ea6e2SKumar Kartikeya Dwivedi }
828af4ea6e2SKumar Kartikeya Dwivedi 
829af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_insn_origin(struct bpf_verifier_env *env, u32 insn_idx,
830af4ea6e2SKumar Kartikeya Dwivedi 				 const struct bpf_diag_mod_target *target,
831af4ea6e2SKumar Kartikeya Dwivedi 				 struct bpf_diag_mod_target *origin)
832af4ea6e2SKumar Kartikeya Dwivedi {
833af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_insn *insn = &env->prog->insnsi[insn_idx];
834af4ea6e2SKumar Kartikeya Dwivedi 	u8 class = BPF_CLASS(insn->code);
835af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_func_state *state;
836af4ea6e2SKumar Kartikeya Dwivedi 
837af4ea6e2SKumar Kartikeya Dwivedi 	if (target->kind == BPF_DIAG_MOD_TARGET_REG && (class == BPF_ALU || class == BPF_ALU64) &&
838af4ea6e2SKumar Kartikeya Dwivedi 	    BPF_OP(insn->code) == BPF_MOV && BPF_SRC(insn->code) == BPF_X) {
839af4ea6e2SKumar Kartikeya Dwivedi 		*origin = diag_reg_target(target->frame_id, target->frameno, insn->src_reg);
840af4ea6e2SKumar Kartikeya Dwivedi 		return true;
841af4ea6e2SKumar Kartikeya Dwivedi 	}
842af4ea6e2SKumar Kartikeya Dwivedi 
843af4ea6e2SKumar Kartikeya Dwivedi 	if ((target->kind != BPF_DIAG_MOD_TARGET_STACK_ARG &&
844af4ea6e2SKumar Kartikeya Dwivedi 	     target->kind != BPF_DIAG_MOD_TARGET_STACK_SLOT) ||
845af4ea6e2SKumar Kartikeya Dwivedi 	    class != BPF_STX)
846af4ea6e2SKumar Kartikeya Dwivedi 		return false;
847af4ea6e2SKumar Kartikeya Dwivedi 
848af4ea6e2SKumar Kartikeya Dwivedi 	state = env->cur_state->frame[env->cur_state->curframe];
849af4ea6e2SKumar Kartikeya Dwivedi 	*origin = diag_reg_target(state->diag_frame_id, state->frameno, insn->src_reg);
850af4ea6e2SKumar Kartikeya Dwivedi 	return true;
851af4ea6e2SKumar Kartikeya Dwivedi }
852af4ea6e2SKumar Kartikeya Dwivedi 
853af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_keeps_lineage(struct bpf_verifier_env *env,
854af4ea6e2SKumar Kartikeya Dwivedi 				   const struct bpf_diag_history_event *event)
855af4ea6e2SKumar Kartikeya Dwivedi {
856af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_insn *insn;
857af4ea6e2SKumar Kartikeya Dwivedi 	u8 class;
858af4ea6e2SKumar Kartikeya Dwivedi 
859af4ea6e2SKumar Kartikeya Dwivedi 	if (event->mod.reason != BPF_DIAG_MOD_WRITE ||
860af4ea6e2SKumar Kartikeya Dwivedi 	    event->mod.target.kind != BPF_DIAG_MOD_TARGET_REG)
861af4ea6e2SKumar Kartikeya Dwivedi 		return false;
862af4ea6e2SKumar Kartikeya Dwivedi 
863af4ea6e2SKumar Kartikeya Dwivedi 	insn = &env->prog->insnsi[event->insn_idx];
864af4ea6e2SKumar Kartikeya Dwivedi 	class = BPF_CLASS(insn->code);
865af4ea6e2SKumar Kartikeya Dwivedi 	if (class != BPF_ALU && class != BPF_ALU64)
866af4ea6e2SKumar Kartikeya Dwivedi 		return false;
867af4ea6e2SKumar Kartikeya Dwivedi 
868af4ea6e2SKumar Kartikeya Dwivedi 	switch (BPF_OP(insn->code)) {
869af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_ADD:
870af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_SUB:
871af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_MUL:
872af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_OR:
873af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_AND:
874af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_LSH:
875af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_RSH:
876af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_ARSH:
877af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_XOR:
878af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_NEG:
879af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_END:
880af4ea6e2SKumar Kartikeya Dwivedi 		return true;
881af4ea6e2SKumar Kartikeya Dwivedi 	default:
882af4ea6e2SKumar Kartikeya Dwivedi 		return false;
883af4ea6e2SKumar Kartikeya Dwivedi 	}
884af4ea6e2SKumar Kartikeya Dwivedi }
885af4ea6e2SKumar Kartikeya Dwivedi 
886af4ea6e2SKumar Kartikeya Dwivedi static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx,
887af4ea6e2SKumar Kartikeya Dwivedi 			    struct bpf_diag_mod_target target,
888af4ea6e2SKumar Kartikeya Dwivedi 			    enum bpf_diag_mod_reason reason,
889af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_reg_state *old_reg,
890af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_reg_state *new_reg,
891af4ea6e2SKumar Kartikeya Dwivedi 			    const struct bpf_diag_mod_target *origin)
892af4ea6e2SKumar Kartikeya Dwivedi {
893af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
894af4ea6e2SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
895af4ea6e2SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_MOD,
896af4ea6e2SKumar Kartikeya Dwivedi 		.mod = {
897af4ea6e2SKumar Kartikeya Dwivedi 			.target = target,
898af4ea6e2SKumar Kartikeya Dwivedi 			.reason = reason,
899af4ea6e2SKumar Kartikeya Dwivedi 		},
900af4ea6e2SKumar Kartikeya Dwivedi 	};
901af4ea6e2SKumar Kartikeya Dwivedi 
902af4ea6e2SKumar Kartikeya Dwivedi 	if (old_reg)
903af4ea6e2SKumar Kartikeya Dwivedi 		diag_snapshot_reg(&event.mod.old, old_reg);
904af4ea6e2SKumar Kartikeya Dwivedi 	if (new_reg)
905af4ea6e2SKumar Kartikeya Dwivedi 		diag_snapshot_reg(&event.mod.new, new_reg);
906af4ea6e2SKumar Kartikeya Dwivedi 	if (origin) {
907af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin = *origin;
908af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin_valid = true;
909af4ea6e2SKumar Kartikeya Dwivedi 	} else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) {
910af4ea6e2SKumar Kartikeya Dwivedi 		event.mod.origin_valid = true;
911af4ea6e2SKumar Kartikeya Dwivedi 	}
912af4ea6e2SKumar Kartikeya Dwivedi 	if (old_reg && new_reg &&
913af4ea6e2SKumar Kartikeya Dwivedi 	    (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) &&
914af4ea6e2SKumar Kartikeya Dwivedi 	    !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) &&
915af4ea6e2SKumar Kartikeya Dwivedi 	    !event.mod.origin_valid &&
916af4ea6e2SKumar Kartikeya Dwivedi 	    diag_mod_keeps_lineage(env, &event))
917af4ea6e2SKumar Kartikeya Dwivedi 		return;
918af4ea6e2SKumar Kartikeya Dwivedi 
919af4ea6e2SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
920af4ea6e2SKumar Kartikeya Dwivedi }
921af4ea6e2SKumar Kartikeya Dwivedi 
922af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_reg_state *target_to_reg(struct bpf_verifier_env *env,
923af4ea6e2SKumar Kartikeya Dwivedi 					   const struct bpf_diag_mod_target *target)
924af4ea6e2SKumar Kartikeya Dwivedi {
925af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_verifier_state *vstate = env->cur_state;
926af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_func_state *state;
927af4ea6e2SKumar Kartikeya Dwivedi 
928af4ea6e2SKumar Kartikeya Dwivedi 	state = target->frameno <= vstate->curframe ? vstate->frame[target->frameno] : NULL;
929af4ea6e2SKumar Kartikeya Dwivedi 
930af4ea6e2SKumar Kartikeya Dwivedi 	if (!state)
931af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
932af4ea6e2SKumar Kartikeya Dwivedi 	if (state->diag_frame_id != target->frame_id)
933af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
934af4ea6e2SKumar Kartikeya Dwivedi 
935af4ea6e2SKumar Kartikeya Dwivedi 	switch (target->kind) {
936af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_REG:
937af4ea6e2SKumar Kartikeya Dwivedi 		if (target->regno >= MAX_BPF_REG)
938af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
939af4ea6e2SKumar Kartikeya Dwivedi 		return &state->regs[target->regno];
940af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_ARG:
941af4ea6e2SKumar Kartikeya Dwivedi 		if (target->stack_arg >= state->out_stack_arg_cnt)
942af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
943af4ea6e2SKumar Kartikeya Dwivedi 		return &state->stack_arg_regs[target->stack_arg];
944af4ea6e2SKumar Kartikeya Dwivedi 	case BPF_DIAG_MOD_TARGET_STACK_SLOT:
945af4ea6e2SKumar Kartikeya Dwivedi 		if (target->spi >= state->allocated_stack / BPF_REG_SIZE)
946af4ea6e2SKumar Kartikeya Dwivedi 			return NULL;
947af4ea6e2SKumar Kartikeya Dwivedi 		return &state->stack[target->spi].spilled_ptr;
948af4ea6e2SKumar Kartikeya Dwivedi 	default:
949af4ea6e2SKumar Kartikeya Dwivedi 		return NULL;
950af4ea6e2SKumar Kartikeya Dwivedi 	}
951af4ea6e2SKumar Kartikeya Dwivedi }
952af4ea6e2SKumar Kartikeya Dwivedi 
953af4ea6e2SKumar Kartikeya Dwivedi static bool reg_to_target(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
954af4ea6e2SKumar Kartikeya Dwivedi 			  struct bpf_diag_mod_target *target)
955af4ea6e2SKumar Kartikeya Dwivedi {
956af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_verifier_state *vstate = env->cur_state;
957af4ea6e2SKumar Kartikeya Dwivedi 	unsigned long addr = (unsigned long)reg;
958af4ea6e2SKumar Kartikeya Dwivedi 	int frame;
959af4ea6e2SKumar Kartikeya Dwivedi 
960af4ea6e2SKumar Kartikeya Dwivedi 	for (frame = 0; frame <= vstate->curframe; frame++) {
961af4ea6e2SKumar Kartikeya Dwivedi 		struct bpf_func_state *state = vstate->frame[frame];
962af4ea6e2SKumar Kartikeya Dwivedi 		unsigned long start, end;
963af4ea6e2SKumar Kartikeya Dwivedi 		u32 nslots = state->allocated_stack / BPF_REG_SIZE;
964af4ea6e2SKumar Kartikeya Dwivedi 		int spi;
965af4ea6e2SKumar Kartikeya Dwivedi 
966af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->regs;
967af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->regs + MAX_BPF_REG);
968af4ea6e2SKumar Kartikeya Dwivedi 		if (addr >= start && addr < end) {
969af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_reg_target(state->diag_frame_id, state->frameno,
970af4ea6e2SKumar Kartikeya Dwivedi 						  reg - state->regs);
971af4ea6e2SKumar Kartikeya Dwivedi 			return true;
972af4ea6e2SKumar Kartikeya Dwivedi 		}
973af4ea6e2SKumar Kartikeya Dwivedi 
974af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->stack_arg_regs;
975af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->stack_arg_regs + state->out_stack_arg_cnt);
976af4ea6e2SKumar Kartikeya Dwivedi 		if (state->out_stack_arg_cnt && addr >= start && addr < end) {
977af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_stack_arg_target(state->diag_frame_id, state->frameno,
978af4ea6e2SKumar Kartikeya Dwivedi 							reg - state->stack_arg_regs);
979af4ea6e2SKumar Kartikeya Dwivedi 			return true;
980af4ea6e2SKumar Kartikeya Dwivedi 		}
981af4ea6e2SKumar Kartikeya Dwivedi 
982af4ea6e2SKumar Kartikeya Dwivedi 		start = (unsigned long)state->stack;
983af4ea6e2SKumar Kartikeya Dwivedi 		end = (unsigned long)(state->stack + nslots);
984af4ea6e2SKumar Kartikeya Dwivedi 		if (nslots && addr >= start && addr < end) {
985af4ea6e2SKumar Kartikeya Dwivedi 			spi = ((const char *)reg - (const char *)state->stack) /
986af4ea6e2SKumar Kartikeya Dwivedi 			      sizeof(*state->stack);
987af4ea6e2SKumar Kartikeya Dwivedi 			*target = diag_stack_slot_target(state->diag_frame_id, state->frameno, spi);
988af4ea6e2SKumar Kartikeya Dwivedi 			return true;
989af4ea6e2SKumar Kartikeya Dwivedi 		}
990af4ea6e2SKumar Kartikeya Dwivedi 	}
991af4ea6e2SKumar Kartikeya Dwivedi 	return false;
992af4ea6e2SKumar Kartikeya Dwivedi }
993af4ea6e2SKumar Kartikeya Dwivedi 
994af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
995af4ea6e2SKumar Kartikeya Dwivedi 			const struct bpf_reg_state *origin, enum bpf_diag_mod_reason reason)
996af4ea6e2SKumar Kartikeya Dwivedi {
997af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
998af4ea6e2SKumar Kartikeya Dwivedi 
999af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag)
1000af4ea6e2SKumar Kartikeya Dwivedi 		return;
1001af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.active = reg_to_target(env, reg, &diag->mod.target);
1002af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag->mod.active)
1003af4ea6e2SKumar Kartikeya Dwivedi 		return;
1004af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.target_reg_snapshot = *reg;
1005af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.insn_idx = env->insn_idx;
1006af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.reason = reason;
1007af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.origin_valid = origin && reg_to_target(env, origin, &diag->mod.origin);
1008af4ea6e2SKumar Kartikeya Dwivedi }
1009af4ea6e2SKumar Kartikeya Dwivedi 
1010af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_end(struct bpf_verifier_env *env)
1011af4ea6e2SKumar Kartikeya Dwivedi {
1012af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag *diag = env->diag;
1013af4ea6e2SKumar Kartikeya Dwivedi 	const struct bpf_reg_state *new_reg;
1014af4ea6e2SKumar Kartikeya Dwivedi 
1015af4ea6e2SKumar Kartikeya Dwivedi 	if (!diag || !diag->mod.active)
1016af4ea6e2SKumar Kartikeya Dwivedi 		return;
1017af4ea6e2SKumar Kartikeya Dwivedi 	diag->mod.active = false;
1018af4ea6e2SKumar Kartikeya Dwivedi 	/*
1019af4ea6e2SKumar Kartikeya Dwivedi 	 * Resolve the target again because the enclosing function state's stack
1020af4ea6e2SKumar Kartikeya Dwivedi 	 * may have been reallocated while the modification was in progress.
1021af4ea6e2SKumar Kartikeya Dwivedi 	 */
1022af4ea6e2SKumar Kartikeya Dwivedi 	new_reg = target_to_reg(env, &diag->mod.target);
1023af4ea6e2SKumar Kartikeya Dwivedi 	if (!new_reg)
1024af4ea6e2SKumar Kartikeya Dwivedi 		return;
1025af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, diag->mod.insn_idx, diag->mod.target, diag->mod.reason,
1026af4ea6e2SKumar Kartikeya Dwivedi 			&diag->mod.target_reg_snapshot, new_reg,
1027af4ea6e2SKumar Kartikeya Dwivedi 			diag->mod.origin_valid ? &diag->mod.origin : NULL);
1028af4ea6e2SKumar Kartikeya Dwivedi }
1029af4ea6e2SKumar Kartikeya Dwivedi 
1030af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub(struct bpf_verifier_env *env, const struct bpf_reg_state *reg,
1031af4ea6e2SKumar Kartikeya Dwivedi 			   enum bpf_diag_mod_reason reason)
1032af4ea6e2SKumar Kartikeya Dwivedi {
1033af4ea6e2SKumar Kartikeya Dwivedi 	struct bpf_diag_mod_target target;
1034af4ea6e2SKumar Kartikeya Dwivedi 
1035af4ea6e2SKumar Kartikeya Dwivedi 	if (!env->diag || reg->type == NOT_INIT || !reg_to_target(env, reg, &target))
1036af4ea6e2SKumar Kartikeya Dwivedi 		return;
1037af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, env->insn_idx, target, reason, reg, NULL, NULL);
1038af4ea6e2SKumar Kartikeya Dwivedi }
1039af4ea6e2SKumar Kartikeya Dwivedi 
1040af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub_stack(struct bpf_verifier_env *env,
1041af4ea6e2SKumar Kartikeya Dwivedi 				 const struct bpf_func_state *state, s16 min_off, s16 max_off,
1042af4ea6e2SKumar Kartikeya Dwivedi 				 enum bpf_diag_mod_reason reason)
1043af4ea6e2SKumar Kartikeya Dwivedi {
1044af4ea6e2SKumar Kartikeya Dwivedi 	diag_record_mod(env, env->insn_idx,
1045af4ea6e2SKumar Kartikeya Dwivedi 			diag_stack_range_target(state->diag_frame_id, state->frameno, min_off, max_off),
1046af4ea6e2SKumar Kartikeya Dwivedi 			reason, NULL, NULL, NULL);
1047af4ea6e2SKumar Kartikeya Dwivedi }
10489ecd7030SKumar Kartikeya Dwivedi 
10499ecd7030SKumar Kartikeya Dwivedi static void diag_record_ref(struct bpf_verifier_env *env, u32 insn_idx, u8 kind, u32 ref_id)
10509ecd7030SKumar Kartikeya Dwivedi {
10519ecd7030SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
10529ecd7030SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
10539ecd7030SKumar Kartikeya Dwivedi 		.kind = kind,
10549ecd7030SKumar Kartikeya Dwivedi 		.ref = {
10559ecd7030SKumar Kartikeya Dwivedi 			.ref_id = ref_id,
10569ecd7030SKumar Kartikeya Dwivedi 		},
10579ecd7030SKumar Kartikeya Dwivedi 	};
10589ecd7030SKumar Kartikeya Dwivedi 
10599ecd7030SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
10609ecd7030SKumar Kartikeya Dwivedi }
10619ecd7030SKumar Kartikeya Dwivedi 
10629ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
10639ecd7030SKumar Kartikeya Dwivedi {
10649ecd7030SKumar Kartikeya Dwivedi 	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_ACQUIRE, ref_id);
10659ecd7030SKumar Kartikeya Dwivedi }
10669ecd7030SKumar Kartikeya Dwivedi 
10679ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id)
10689ecd7030SKumar Kartikeya Dwivedi {
10699ecd7030SKumar Kartikeya Dwivedi 	diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id);
10709ecd7030SKumar Kartikeya Dwivedi }
1071*956a66e5SKumar Kartikeya Dwivedi 
1072*956a66e5SKumar Kartikeya Dwivedi void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx,
1073*956a66e5SKumar Kartikeya Dwivedi 			     enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth)
1074*956a66e5SKumar Kartikeya Dwivedi {
1075*956a66e5SKumar Kartikeya Dwivedi 	/*
1076*956a66e5SKumar Kartikeya Dwivedi 	 * Keep leave events so context rendering can stop at a depth-zero exit
1077*956a66e5SKumar Kartikeya Dwivedi 	 * and show nested-region depth accurately for the active path.
1078*956a66e5SKumar Kartikeya Dwivedi 	 */
1079*956a66e5SKumar Kartikeya Dwivedi 	struct bpf_diag_history_event event = {
1080*956a66e5SKumar Kartikeya Dwivedi 		.insn_idx = insn_idx,
1081*956a66e5SKumar Kartikeya Dwivedi 		.kind = BPF_DIAG_HISTORY_CONTEXT,
1082*956a66e5SKumar Kartikeya Dwivedi 		.ctx = {
1083*956a66e5SKumar Kartikeya Dwivedi 			.kind = ctx_kind,
1084*956a66e5SKumar Kartikeya Dwivedi 			.enter = enter,
1085*956a66e5SKumar Kartikeya Dwivedi 			.depth = depth,
1086*956a66e5SKumar Kartikeya Dwivedi 		},
1087*956a66e5SKumar Kartikeya Dwivedi 	};
1088*956a66e5SKumar Kartikeya Dwivedi 
1089*956a66e5SKumar Kartikeya Dwivedi 	diag_append_history(env, &event);
1090*956a66e5SKumar Kartikeya Dwivedi }
1091