xref: /linux/kernel/bpf/check_btf.c (revision f5ad4101009e7f5f5984ffea6923d4fcd470932a)
1*99a832a2SAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0-only
2*99a832a2SAlexei Starovoitov /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3*99a832a2SAlexei Starovoitov #include <linux/bpf.h>
4*99a832a2SAlexei Starovoitov #include <linux/bpf_verifier.h>
5*99a832a2SAlexei Starovoitov #include <linux/filter.h>
6*99a832a2SAlexei Starovoitov #include <linux/btf.h>
7*99a832a2SAlexei Starovoitov 
8*99a832a2SAlexei Starovoitov #define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
9*99a832a2SAlexei Starovoitov 
10*99a832a2SAlexei Starovoitov static int check_abnormal_return(struct bpf_verifier_env *env)
11*99a832a2SAlexei Starovoitov {
12*99a832a2SAlexei Starovoitov 	int i;
13*99a832a2SAlexei Starovoitov 
14*99a832a2SAlexei Starovoitov 	for (i = 1; i < env->subprog_cnt; i++) {
15*99a832a2SAlexei Starovoitov 		if (env->subprog_info[i].has_ld_abs) {
16*99a832a2SAlexei Starovoitov 			verbose(env, "LD_ABS is not allowed in subprogs without BTF\n");
17*99a832a2SAlexei Starovoitov 			return -EINVAL;
18*99a832a2SAlexei Starovoitov 		}
19*99a832a2SAlexei Starovoitov 		if (env->subprog_info[i].has_tail_call) {
20*99a832a2SAlexei Starovoitov 			verbose(env, "tail_call is not allowed in subprogs without BTF\n");
21*99a832a2SAlexei Starovoitov 			return -EINVAL;
22*99a832a2SAlexei Starovoitov 		}
23*99a832a2SAlexei Starovoitov 	}
24*99a832a2SAlexei Starovoitov 	return 0;
25*99a832a2SAlexei Starovoitov }
26*99a832a2SAlexei Starovoitov 
27*99a832a2SAlexei Starovoitov /* The minimum supported BTF func info size */
28*99a832a2SAlexei Starovoitov #define MIN_BPF_FUNCINFO_SIZE	8
29*99a832a2SAlexei Starovoitov #define MAX_FUNCINFO_REC_SIZE	252
30*99a832a2SAlexei Starovoitov 
31*99a832a2SAlexei Starovoitov static int check_btf_func_early(struct bpf_verifier_env *env,
32*99a832a2SAlexei Starovoitov 				const union bpf_attr *attr,
33*99a832a2SAlexei Starovoitov 				bpfptr_t uattr)
34*99a832a2SAlexei Starovoitov {
35*99a832a2SAlexei Starovoitov 	u32 krec_size = sizeof(struct bpf_func_info);
36*99a832a2SAlexei Starovoitov 	const struct btf_type *type, *func_proto;
37*99a832a2SAlexei Starovoitov 	u32 i, nfuncs, urec_size, min_size;
38*99a832a2SAlexei Starovoitov 	struct bpf_func_info *krecord;
39*99a832a2SAlexei Starovoitov 	struct bpf_prog *prog;
40*99a832a2SAlexei Starovoitov 	const struct btf *btf;
41*99a832a2SAlexei Starovoitov 	u32 prev_offset = 0;
42*99a832a2SAlexei Starovoitov 	bpfptr_t urecord;
43*99a832a2SAlexei Starovoitov 	int ret = -ENOMEM;
44*99a832a2SAlexei Starovoitov 
45*99a832a2SAlexei Starovoitov 	nfuncs = attr->func_info_cnt;
46*99a832a2SAlexei Starovoitov 	if (!nfuncs) {
47*99a832a2SAlexei Starovoitov 		if (check_abnormal_return(env))
48*99a832a2SAlexei Starovoitov 			return -EINVAL;
49*99a832a2SAlexei Starovoitov 		return 0;
50*99a832a2SAlexei Starovoitov 	}
51*99a832a2SAlexei Starovoitov 
52*99a832a2SAlexei Starovoitov 	urec_size = attr->func_info_rec_size;
53*99a832a2SAlexei Starovoitov 	if (urec_size < MIN_BPF_FUNCINFO_SIZE ||
54*99a832a2SAlexei Starovoitov 	    urec_size > MAX_FUNCINFO_REC_SIZE ||
55*99a832a2SAlexei Starovoitov 	    urec_size % sizeof(u32)) {
56*99a832a2SAlexei Starovoitov 		verbose(env, "invalid func info rec size %u\n", urec_size);
57*99a832a2SAlexei Starovoitov 		return -EINVAL;
58*99a832a2SAlexei Starovoitov 	}
59*99a832a2SAlexei Starovoitov 
60*99a832a2SAlexei Starovoitov 	prog = env->prog;
61*99a832a2SAlexei Starovoitov 	btf = prog->aux->btf;
62*99a832a2SAlexei Starovoitov 
63*99a832a2SAlexei Starovoitov 	urecord = make_bpfptr(attr->func_info, uattr.is_kernel);
64*99a832a2SAlexei Starovoitov 	min_size = min_t(u32, krec_size, urec_size);
65*99a832a2SAlexei Starovoitov 
66*99a832a2SAlexei Starovoitov 	krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
67*99a832a2SAlexei Starovoitov 	if (!krecord)
68*99a832a2SAlexei Starovoitov 		return -ENOMEM;
69*99a832a2SAlexei Starovoitov 
70*99a832a2SAlexei Starovoitov 	for (i = 0; i < nfuncs; i++) {
71*99a832a2SAlexei Starovoitov 		ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size);
72*99a832a2SAlexei Starovoitov 		if (ret) {
73*99a832a2SAlexei Starovoitov 			if (ret == -E2BIG) {
74*99a832a2SAlexei Starovoitov 				verbose(env, "nonzero tailing record in func info");
75*99a832a2SAlexei Starovoitov 				/* set the size kernel expects so loader can zero
76*99a832a2SAlexei Starovoitov 				 * out the rest of the record.
77*99a832a2SAlexei Starovoitov 				 */
78*99a832a2SAlexei Starovoitov 				if (copy_to_bpfptr_offset(uattr,
79*99a832a2SAlexei Starovoitov 							  offsetof(union bpf_attr, func_info_rec_size),
80*99a832a2SAlexei Starovoitov 							  &min_size, sizeof(min_size)))
81*99a832a2SAlexei Starovoitov 					ret = -EFAULT;
82*99a832a2SAlexei Starovoitov 			}
83*99a832a2SAlexei Starovoitov 			goto err_free;
84*99a832a2SAlexei Starovoitov 		}
85*99a832a2SAlexei Starovoitov 
86*99a832a2SAlexei Starovoitov 		if (copy_from_bpfptr(&krecord[i], urecord, min_size)) {
87*99a832a2SAlexei Starovoitov 			ret = -EFAULT;
88*99a832a2SAlexei Starovoitov 			goto err_free;
89*99a832a2SAlexei Starovoitov 		}
90*99a832a2SAlexei Starovoitov 
91*99a832a2SAlexei Starovoitov 		/* check insn_off */
92*99a832a2SAlexei Starovoitov 		ret = -EINVAL;
93*99a832a2SAlexei Starovoitov 		if (i == 0) {
94*99a832a2SAlexei Starovoitov 			if (krecord[i].insn_off) {
95*99a832a2SAlexei Starovoitov 				verbose(env,
96*99a832a2SAlexei Starovoitov 					"nonzero insn_off %u for the first func info record",
97*99a832a2SAlexei Starovoitov 					krecord[i].insn_off);
98*99a832a2SAlexei Starovoitov 				goto err_free;
99*99a832a2SAlexei Starovoitov 			}
100*99a832a2SAlexei Starovoitov 		} else if (krecord[i].insn_off <= prev_offset) {
101*99a832a2SAlexei Starovoitov 			verbose(env,
102*99a832a2SAlexei Starovoitov 				"same or smaller insn offset (%u) than previous func info record (%u)",
103*99a832a2SAlexei Starovoitov 				krecord[i].insn_off, prev_offset);
104*99a832a2SAlexei Starovoitov 			goto err_free;
105*99a832a2SAlexei Starovoitov 		}
106*99a832a2SAlexei Starovoitov 
107*99a832a2SAlexei Starovoitov 		/* check type_id */
108*99a832a2SAlexei Starovoitov 		type = btf_type_by_id(btf, krecord[i].type_id);
109*99a832a2SAlexei Starovoitov 		if (!type || !btf_type_is_func(type)) {
110*99a832a2SAlexei Starovoitov 			verbose(env, "invalid type id %d in func info",
111*99a832a2SAlexei Starovoitov 				krecord[i].type_id);
112*99a832a2SAlexei Starovoitov 			goto err_free;
113*99a832a2SAlexei Starovoitov 		}
114*99a832a2SAlexei Starovoitov 
115*99a832a2SAlexei Starovoitov 		func_proto = btf_type_by_id(btf, type->type);
116*99a832a2SAlexei Starovoitov 		if (unlikely(!func_proto || !btf_type_is_func_proto(func_proto)))
117*99a832a2SAlexei Starovoitov 			/* btf_func_check() already verified it during BTF load */
118*99a832a2SAlexei Starovoitov 			goto err_free;
119*99a832a2SAlexei Starovoitov 
120*99a832a2SAlexei Starovoitov 		prev_offset = krecord[i].insn_off;
121*99a832a2SAlexei Starovoitov 		bpfptr_add(&urecord, urec_size);
122*99a832a2SAlexei Starovoitov 	}
123*99a832a2SAlexei Starovoitov 
124*99a832a2SAlexei Starovoitov 	prog->aux->func_info = krecord;
125*99a832a2SAlexei Starovoitov 	prog->aux->func_info_cnt = nfuncs;
126*99a832a2SAlexei Starovoitov 	return 0;
127*99a832a2SAlexei Starovoitov 
128*99a832a2SAlexei Starovoitov err_free:
129*99a832a2SAlexei Starovoitov 	kvfree(krecord);
130*99a832a2SAlexei Starovoitov 	return ret;
131*99a832a2SAlexei Starovoitov }
132*99a832a2SAlexei Starovoitov 
133*99a832a2SAlexei Starovoitov static int check_btf_func(struct bpf_verifier_env *env,
134*99a832a2SAlexei Starovoitov 			  const union bpf_attr *attr,
135*99a832a2SAlexei Starovoitov 			  bpfptr_t uattr)
136*99a832a2SAlexei Starovoitov {
137*99a832a2SAlexei Starovoitov 	const struct btf_type *type, *func_proto, *ret_type;
138*99a832a2SAlexei Starovoitov 	u32 i, nfuncs, urec_size;
139*99a832a2SAlexei Starovoitov 	struct bpf_func_info *krecord;
140*99a832a2SAlexei Starovoitov 	struct bpf_func_info_aux *info_aux = NULL;
141*99a832a2SAlexei Starovoitov 	struct bpf_prog *prog;
142*99a832a2SAlexei Starovoitov 	const struct btf *btf;
143*99a832a2SAlexei Starovoitov 	bpfptr_t urecord;
144*99a832a2SAlexei Starovoitov 	bool scalar_return;
145*99a832a2SAlexei Starovoitov 	int ret = -ENOMEM;
146*99a832a2SAlexei Starovoitov 
147*99a832a2SAlexei Starovoitov 	nfuncs = attr->func_info_cnt;
148*99a832a2SAlexei Starovoitov 	if (!nfuncs) {
149*99a832a2SAlexei Starovoitov 		if (check_abnormal_return(env))
150*99a832a2SAlexei Starovoitov 			return -EINVAL;
151*99a832a2SAlexei Starovoitov 		return 0;
152*99a832a2SAlexei Starovoitov 	}
153*99a832a2SAlexei Starovoitov 	if (nfuncs != env->subprog_cnt) {
154*99a832a2SAlexei Starovoitov 		verbose(env, "number of funcs in func_info doesn't match number of subprogs\n");
155*99a832a2SAlexei Starovoitov 		return -EINVAL;
156*99a832a2SAlexei Starovoitov 	}
157*99a832a2SAlexei Starovoitov 
158*99a832a2SAlexei Starovoitov 	urec_size = attr->func_info_rec_size;
159*99a832a2SAlexei Starovoitov 
160*99a832a2SAlexei Starovoitov 	prog = env->prog;
161*99a832a2SAlexei Starovoitov 	btf = prog->aux->btf;
162*99a832a2SAlexei Starovoitov 
163*99a832a2SAlexei Starovoitov 	urecord = make_bpfptr(attr->func_info, uattr.is_kernel);
164*99a832a2SAlexei Starovoitov 
165*99a832a2SAlexei Starovoitov 	krecord = prog->aux->func_info;
166*99a832a2SAlexei Starovoitov 	info_aux = kzalloc_objs(*info_aux, nfuncs,
167*99a832a2SAlexei Starovoitov 				GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
168*99a832a2SAlexei Starovoitov 	if (!info_aux)
169*99a832a2SAlexei Starovoitov 		return -ENOMEM;
170*99a832a2SAlexei Starovoitov 
171*99a832a2SAlexei Starovoitov 	for (i = 0; i < nfuncs; i++) {
172*99a832a2SAlexei Starovoitov 		/* check insn_off */
173*99a832a2SAlexei Starovoitov 		ret = -EINVAL;
174*99a832a2SAlexei Starovoitov 
175*99a832a2SAlexei Starovoitov 		if (env->subprog_info[i].start != krecord[i].insn_off) {
176*99a832a2SAlexei Starovoitov 			verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
177*99a832a2SAlexei Starovoitov 			goto err_free;
178*99a832a2SAlexei Starovoitov 		}
179*99a832a2SAlexei Starovoitov 
180*99a832a2SAlexei Starovoitov 		/* Already checked type_id */
181*99a832a2SAlexei Starovoitov 		type = btf_type_by_id(btf, krecord[i].type_id);
182*99a832a2SAlexei Starovoitov 		info_aux[i].linkage = BTF_INFO_VLEN(type->info);
183*99a832a2SAlexei Starovoitov 		/* Already checked func_proto */
184*99a832a2SAlexei Starovoitov 		func_proto = btf_type_by_id(btf, type->type);
185*99a832a2SAlexei Starovoitov 
186*99a832a2SAlexei Starovoitov 		ret_type = btf_type_skip_modifiers(btf, func_proto->type, NULL);
187*99a832a2SAlexei Starovoitov 		scalar_return =
188*99a832a2SAlexei Starovoitov 			btf_type_is_small_int(ret_type) || btf_is_any_enum(ret_type);
189*99a832a2SAlexei Starovoitov 		if (i && !scalar_return && env->subprog_info[i].has_ld_abs) {
190*99a832a2SAlexei Starovoitov 			verbose(env, "LD_ABS is only allowed in functions that return 'int'.\n");
191*99a832a2SAlexei Starovoitov 			goto err_free;
192*99a832a2SAlexei Starovoitov 		}
193*99a832a2SAlexei Starovoitov 		if (i && !scalar_return && env->subprog_info[i].has_tail_call) {
194*99a832a2SAlexei Starovoitov 			verbose(env, "tail_call is only allowed in functions that return 'int'.\n");
195*99a832a2SAlexei Starovoitov 			goto err_free;
196*99a832a2SAlexei Starovoitov 		}
197*99a832a2SAlexei Starovoitov 
198*99a832a2SAlexei Starovoitov 		env->subprog_info[i].name = btf_name_by_offset(btf, type->name_off);
199*99a832a2SAlexei Starovoitov 		bpfptr_add(&urecord, urec_size);
200*99a832a2SAlexei Starovoitov 	}
201*99a832a2SAlexei Starovoitov 
202*99a832a2SAlexei Starovoitov 	prog->aux->func_info_aux = info_aux;
203*99a832a2SAlexei Starovoitov 	return 0;
204*99a832a2SAlexei Starovoitov 
205*99a832a2SAlexei Starovoitov err_free:
206*99a832a2SAlexei Starovoitov 	kfree(info_aux);
207*99a832a2SAlexei Starovoitov 	return ret;
208*99a832a2SAlexei Starovoitov }
209*99a832a2SAlexei Starovoitov 
210*99a832a2SAlexei Starovoitov #define MIN_BPF_LINEINFO_SIZE	offsetofend(struct bpf_line_info, line_col)
211*99a832a2SAlexei Starovoitov #define MAX_LINEINFO_REC_SIZE	MAX_FUNCINFO_REC_SIZE
212*99a832a2SAlexei Starovoitov 
213*99a832a2SAlexei Starovoitov static int check_btf_line(struct bpf_verifier_env *env,
214*99a832a2SAlexei Starovoitov 			  const union bpf_attr *attr,
215*99a832a2SAlexei Starovoitov 			  bpfptr_t uattr)
216*99a832a2SAlexei Starovoitov {
217*99a832a2SAlexei Starovoitov 	u32 i, s, nr_linfo, ncopy, expected_size, rec_size, prev_offset = 0;
218*99a832a2SAlexei Starovoitov 	struct bpf_subprog_info *sub;
219*99a832a2SAlexei Starovoitov 	struct bpf_line_info *linfo;
220*99a832a2SAlexei Starovoitov 	struct bpf_prog *prog;
221*99a832a2SAlexei Starovoitov 	const struct btf *btf;
222*99a832a2SAlexei Starovoitov 	bpfptr_t ulinfo;
223*99a832a2SAlexei Starovoitov 	int err;
224*99a832a2SAlexei Starovoitov 
225*99a832a2SAlexei Starovoitov 	nr_linfo = attr->line_info_cnt;
226*99a832a2SAlexei Starovoitov 	if (!nr_linfo)
227*99a832a2SAlexei Starovoitov 		return 0;
228*99a832a2SAlexei Starovoitov 	if (nr_linfo > INT_MAX / sizeof(struct bpf_line_info))
229*99a832a2SAlexei Starovoitov 		return -EINVAL;
230*99a832a2SAlexei Starovoitov 
231*99a832a2SAlexei Starovoitov 	rec_size = attr->line_info_rec_size;
232*99a832a2SAlexei Starovoitov 	if (rec_size < MIN_BPF_LINEINFO_SIZE ||
233*99a832a2SAlexei Starovoitov 	    rec_size > MAX_LINEINFO_REC_SIZE ||
234*99a832a2SAlexei Starovoitov 	    rec_size & (sizeof(u32) - 1))
235*99a832a2SAlexei Starovoitov 		return -EINVAL;
236*99a832a2SAlexei Starovoitov 
237*99a832a2SAlexei Starovoitov 	/* Need to zero it in case the userspace may
238*99a832a2SAlexei Starovoitov 	 * pass in a smaller bpf_line_info object.
239*99a832a2SAlexei Starovoitov 	 */
240*99a832a2SAlexei Starovoitov 	linfo = kvzalloc_objs(struct bpf_line_info, nr_linfo,
241*99a832a2SAlexei Starovoitov 			      GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
242*99a832a2SAlexei Starovoitov 	if (!linfo)
243*99a832a2SAlexei Starovoitov 		return -ENOMEM;
244*99a832a2SAlexei Starovoitov 
245*99a832a2SAlexei Starovoitov 	prog = env->prog;
246*99a832a2SAlexei Starovoitov 	btf = prog->aux->btf;
247*99a832a2SAlexei Starovoitov 
248*99a832a2SAlexei Starovoitov 	s = 0;
249*99a832a2SAlexei Starovoitov 	sub = env->subprog_info;
250*99a832a2SAlexei Starovoitov 	ulinfo = make_bpfptr(attr->line_info, uattr.is_kernel);
251*99a832a2SAlexei Starovoitov 	expected_size = sizeof(struct bpf_line_info);
252*99a832a2SAlexei Starovoitov 	ncopy = min_t(u32, expected_size, rec_size);
253*99a832a2SAlexei Starovoitov 	for (i = 0; i < nr_linfo; i++) {
254*99a832a2SAlexei Starovoitov 		err = bpf_check_uarg_tail_zero(ulinfo, expected_size, rec_size);
255*99a832a2SAlexei Starovoitov 		if (err) {
256*99a832a2SAlexei Starovoitov 			if (err == -E2BIG) {
257*99a832a2SAlexei Starovoitov 				verbose(env, "nonzero tailing record in line_info");
258*99a832a2SAlexei Starovoitov 				if (copy_to_bpfptr_offset(uattr,
259*99a832a2SAlexei Starovoitov 							  offsetof(union bpf_attr, line_info_rec_size),
260*99a832a2SAlexei Starovoitov 							  &expected_size, sizeof(expected_size)))
261*99a832a2SAlexei Starovoitov 					err = -EFAULT;
262*99a832a2SAlexei Starovoitov 			}
263*99a832a2SAlexei Starovoitov 			goto err_free;
264*99a832a2SAlexei Starovoitov 		}
265*99a832a2SAlexei Starovoitov 
266*99a832a2SAlexei Starovoitov 		if (copy_from_bpfptr(&linfo[i], ulinfo, ncopy)) {
267*99a832a2SAlexei Starovoitov 			err = -EFAULT;
268*99a832a2SAlexei Starovoitov 			goto err_free;
269*99a832a2SAlexei Starovoitov 		}
270*99a832a2SAlexei Starovoitov 
271*99a832a2SAlexei Starovoitov 		/*
272*99a832a2SAlexei Starovoitov 		 * Check insn_off to ensure
273*99a832a2SAlexei Starovoitov 		 * 1) strictly increasing AND
274*99a832a2SAlexei Starovoitov 		 * 2) bounded by prog->len
275*99a832a2SAlexei Starovoitov 		 *
276*99a832a2SAlexei Starovoitov 		 * The linfo[0].insn_off == 0 check logically falls into
277*99a832a2SAlexei Starovoitov 		 * the later "missing bpf_line_info for func..." case
278*99a832a2SAlexei Starovoitov 		 * because the first linfo[0].insn_off must be the
279*99a832a2SAlexei Starovoitov 		 * first sub also and the first sub must have
280*99a832a2SAlexei Starovoitov 		 * subprog_info[0].start == 0.
281*99a832a2SAlexei Starovoitov 		 */
282*99a832a2SAlexei Starovoitov 		if ((i && linfo[i].insn_off <= prev_offset) ||
283*99a832a2SAlexei Starovoitov 		    linfo[i].insn_off >= prog->len) {
284*99a832a2SAlexei Starovoitov 			verbose(env, "Invalid line_info[%u].insn_off:%u (prev_offset:%u prog->len:%u)\n",
285*99a832a2SAlexei Starovoitov 				i, linfo[i].insn_off, prev_offset,
286*99a832a2SAlexei Starovoitov 				prog->len);
287*99a832a2SAlexei Starovoitov 			err = -EINVAL;
288*99a832a2SAlexei Starovoitov 			goto err_free;
289*99a832a2SAlexei Starovoitov 		}
290*99a832a2SAlexei Starovoitov 
291*99a832a2SAlexei Starovoitov 		if (!prog->insnsi[linfo[i].insn_off].code) {
292*99a832a2SAlexei Starovoitov 			verbose(env,
293*99a832a2SAlexei Starovoitov 				"Invalid insn code at line_info[%u].insn_off\n",
294*99a832a2SAlexei Starovoitov 				i);
295*99a832a2SAlexei Starovoitov 			err = -EINVAL;
296*99a832a2SAlexei Starovoitov 			goto err_free;
297*99a832a2SAlexei Starovoitov 		}
298*99a832a2SAlexei Starovoitov 
299*99a832a2SAlexei Starovoitov 		if (!btf_name_by_offset(btf, linfo[i].line_off) ||
300*99a832a2SAlexei Starovoitov 		    !btf_name_by_offset(btf, linfo[i].file_name_off)) {
301*99a832a2SAlexei Starovoitov 			verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i);
302*99a832a2SAlexei Starovoitov 			err = -EINVAL;
303*99a832a2SAlexei Starovoitov 			goto err_free;
304*99a832a2SAlexei Starovoitov 		}
305*99a832a2SAlexei Starovoitov 
306*99a832a2SAlexei Starovoitov 		if (s != env->subprog_cnt) {
307*99a832a2SAlexei Starovoitov 			if (linfo[i].insn_off == sub[s].start) {
308*99a832a2SAlexei Starovoitov 				sub[s].linfo_idx = i;
309*99a832a2SAlexei Starovoitov 				s++;
310*99a832a2SAlexei Starovoitov 			} else if (sub[s].start < linfo[i].insn_off) {
311*99a832a2SAlexei Starovoitov 				verbose(env, "missing bpf_line_info for func#%u\n", s);
312*99a832a2SAlexei Starovoitov 				err = -EINVAL;
313*99a832a2SAlexei Starovoitov 				goto err_free;
314*99a832a2SAlexei Starovoitov 			}
315*99a832a2SAlexei Starovoitov 		}
316*99a832a2SAlexei Starovoitov 
317*99a832a2SAlexei Starovoitov 		prev_offset = linfo[i].insn_off;
318*99a832a2SAlexei Starovoitov 		bpfptr_add(&ulinfo, rec_size);
319*99a832a2SAlexei Starovoitov 	}
320*99a832a2SAlexei Starovoitov 
321*99a832a2SAlexei Starovoitov 	if (s != env->subprog_cnt) {
322*99a832a2SAlexei Starovoitov 		verbose(env, "missing bpf_line_info for %u funcs starting from func#%u\n",
323*99a832a2SAlexei Starovoitov 			env->subprog_cnt - s, s);
324*99a832a2SAlexei Starovoitov 		err = -EINVAL;
325*99a832a2SAlexei Starovoitov 		goto err_free;
326*99a832a2SAlexei Starovoitov 	}
327*99a832a2SAlexei Starovoitov 
328*99a832a2SAlexei Starovoitov 	prog->aux->linfo = linfo;
329*99a832a2SAlexei Starovoitov 	prog->aux->nr_linfo = nr_linfo;
330*99a832a2SAlexei Starovoitov 
331*99a832a2SAlexei Starovoitov 	return 0;
332*99a832a2SAlexei Starovoitov 
333*99a832a2SAlexei Starovoitov err_free:
334*99a832a2SAlexei Starovoitov 	kvfree(linfo);
335*99a832a2SAlexei Starovoitov 	return err;
336*99a832a2SAlexei Starovoitov }
337*99a832a2SAlexei Starovoitov 
338*99a832a2SAlexei Starovoitov #define MIN_CORE_RELO_SIZE	sizeof(struct bpf_core_relo)
339*99a832a2SAlexei Starovoitov #define MAX_CORE_RELO_SIZE	MAX_FUNCINFO_REC_SIZE
340*99a832a2SAlexei Starovoitov 
341*99a832a2SAlexei Starovoitov static int check_core_relo(struct bpf_verifier_env *env,
342*99a832a2SAlexei Starovoitov 			   const union bpf_attr *attr,
343*99a832a2SAlexei Starovoitov 			   bpfptr_t uattr)
344*99a832a2SAlexei Starovoitov {
345*99a832a2SAlexei Starovoitov 	u32 i, nr_core_relo, ncopy, expected_size, rec_size;
346*99a832a2SAlexei Starovoitov 	struct bpf_core_relo core_relo = {};
347*99a832a2SAlexei Starovoitov 	struct bpf_prog *prog = env->prog;
348*99a832a2SAlexei Starovoitov 	const struct btf *btf = prog->aux->btf;
349*99a832a2SAlexei Starovoitov 	struct bpf_core_ctx ctx = {
350*99a832a2SAlexei Starovoitov 		.log = &env->log,
351*99a832a2SAlexei Starovoitov 		.btf = btf,
352*99a832a2SAlexei Starovoitov 	};
353*99a832a2SAlexei Starovoitov 	bpfptr_t u_core_relo;
354*99a832a2SAlexei Starovoitov 	int err;
355*99a832a2SAlexei Starovoitov 
356*99a832a2SAlexei Starovoitov 	nr_core_relo = attr->core_relo_cnt;
357*99a832a2SAlexei Starovoitov 	if (!nr_core_relo)
358*99a832a2SAlexei Starovoitov 		return 0;
359*99a832a2SAlexei Starovoitov 	if (nr_core_relo > INT_MAX / sizeof(struct bpf_core_relo))
360*99a832a2SAlexei Starovoitov 		return -EINVAL;
361*99a832a2SAlexei Starovoitov 
362*99a832a2SAlexei Starovoitov 	rec_size = attr->core_relo_rec_size;
363*99a832a2SAlexei Starovoitov 	if (rec_size < MIN_CORE_RELO_SIZE ||
364*99a832a2SAlexei Starovoitov 	    rec_size > MAX_CORE_RELO_SIZE ||
365*99a832a2SAlexei Starovoitov 	    rec_size % sizeof(u32))
366*99a832a2SAlexei Starovoitov 		return -EINVAL;
367*99a832a2SAlexei Starovoitov 
368*99a832a2SAlexei Starovoitov 	u_core_relo = make_bpfptr(attr->core_relos, uattr.is_kernel);
369*99a832a2SAlexei Starovoitov 	expected_size = sizeof(struct bpf_core_relo);
370*99a832a2SAlexei Starovoitov 	ncopy = min_t(u32, expected_size, rec_size);
371*99a832a2SAlexei Starovoitov 
372*99a832a2SAlexei Starovoitov 	/* Unlike func_info and line_info, copy and apply each CO-RE
373*99a832a2SAlexei Starovoitov 	 * relocation record one at a time.
374*99a832a2SAlexei Starovoitov 	 */
375*99a832a2SAlexei Starovoitov 	for (i = 0; i < nr_core_relo; i++) {
376*99a832a2SAlexei Starovoitov 		/* future proofing when sizeof(bpf_core_relo) changes */
377*99a832a2SAlexei Starovoitov 		err = bpf_check_uarg_tail_zero(u_core_relo, expected_size, rec_size);
378*99a832a2SAlexei Starovoitov 		if (err) {
379*99a832a2SAlexei Starovoitov 			if (err == -E2BIG) {
380*99a832a2SAlexei Starovoitov 				verbose(env, "nonzero tailing record in core_relo");
381*99a832a2SAlexei Starovoitov 				if (copy_to_bpfptr_offset(uattr,
382*99a832a2SAlexei Starovoitov 							  offsetof(union bpf_attr, core_relo_rec_size),
383*99a832a2SAlexei Starovoitov 							  &expected_size, sizeof(expected_size)))
384*99a832a2SAlexei Starovoitov 					err = -EFAULT;
385*99a832a2SAlexei Starovoitov 			}
386*99a832a2SAlexei Starovoitov 			break;
387*99a832a2SAlexei Starovoitov 		}
388*99a832a2SAlexei Starovoitov 
389*99a832a2SAlexei Starovoitov 		if (copy_from_bpfptr(&core_relo, u_core_relo, ncopy)) {
390*99a832a2SAlexei Starovoitov 			err = -EFAULT;
391*99a832a2SAlexei Starovoitov 			break;
392*99a832a2SAlexei Starovoitov 		}
393*99a832a2SAlexei Starovoitov 
394*99a832a2SAlexei Starovoitov 		if (core_relo.insn_off % 8 || core_relo.insn_off / 8 >= prog->len) {
395*99a832a2SAlexei Starovoitov 			verbose(env, "Invalid core_relo[%u].insn_off:%u prog->len:%u\n",
396*99a832a2SAlexei Starovoitov 				i, core_relo.insn_off, prog->len);
397*99a832a2SAlexei Starovoitov 			err = -EINVAL;
398*99a832a2SAlexei Starovoitov 			break;
399*99a832a2SAlexei Starovoitov 		}
400*99a832a2SAlexei Starovoitov 
401*99a832a2SAlexei Starovoitov 		err = bpf_core_apply(&ctx, &core_relo, i,
402*99a832a2SAlexei Starovoitov 				     &prog->insnsi[core_relo.insn_off / 8]);
403*99a832a2SAlexei Starovoitov 		if (err)
404*99a832a2SAlexei Starovoitov 			break;
405*99a832a2SAlexei Starovoitov 		bpfptr_add(&u_core_relo, rec_size);
406*99a832a2SAlexei Starovoitov 	}
407*99a832a2SAlexei Starovoitov 	return err;
408*99a832a2SAlexei Starovoitov }
409*99a832a2SAlexei Starovoitov 
410*99a832a2SAlexei Starovoitov int bpf_check_btf_info_early(struct bpf_verifier_env *env,
411*99a832a2SAlexei Starovoitov 			     const union bpf_attr *attr,
412*99a832a2SAlexei Starovoitov 			     bpfptr_t uattr)
413*99a832a2SAlexei Starovoitov {
414*99a832a2SAlexei Starovoitov 	struct btf *btf;
415*99a832a2SAlexei Starovoitov 	int err;
416*99a832a2SAlexei Starovoitov 
417*99a832a2SAlexei Starovoitov 	if (!attr->func_info_cnt && !attr->line_info_cnt) {
418*99a832a2SAlexei Starovoitov 		if (check_abnormal_return(env))
419*99a832a2SAlexei Starovoitov 			return -EINVAL;
420*99a832a2SAlexei Starovoitov 		return 0;
421*99a832a2SAlexei Starovoitov 	}
422*99a832a2SAlexei Starovoitov 
423*99a832a2SAlexei Starovoitov 	btf = btf_get_by_fd(attr->prog_btf_fd);
424*99a832a2SAlexei Starovoitov 	if (IS_ERR(btf))
425*99a832a2SAlexei Starovoitov 		return PTR_ERR(btf);
426*99a832a2SAlexei Starovoitov 	if (btf_is_kernel(btf)) {
427*99a832a2SAlexei Starovoitov 		btf_put(btf);
428*99a832a2SAlexei Starovoitov 		return -EACCES;
429*99a832a2SAlexei Starovoitov 	}
430*99a832a2SAlexei Starovoitov 	env->prog->aux->btf = btf;
431*99a832a2SAlexei Starovoitov 
432*99a832a2SAlexei Starovoitov 	err = check_btf_func_early(env, attr, uattr);
433*99a832a2SAlexei Starovoitov 	if (err)
434*99a832a2SAlexei Starovoitov 		return err;
435*99a832a2SAlexei Starovoitov 	return 0;
436*99a832a2SAlexei Starovoitov }
437*99a832a2SAlexei Starovoitov 
438*99a832a2SAlexei Starovoitov int bpf_check_btf_info(struct bpf_verifier_env *env,
439*99a832a2SAlexei Starovoitov 		       const union bpf_attr *attr,
440*99a832a2SAlexei Starovoitov 		       bpfptr_t uattr)
441*99a832a2SAlexei Starovoitov {
442*99a832a2SAlexei Starovoitov 	int err;
443*99a832a2SAlexei Starovoitov 
444*99a832a2SAlexei Starovoitov 	if (!attr->func_info_cnt && !attr->line_info_cnt) {
445*99a832a2SAlexei Starovoitov 		if (check_abnormal_return(env))
446*99a832a2SAlexei Starovoitov 			return -EINVAL;
447*99a832a2SAlexei Starovoitov 		return 0;
448*99a832a2SAlexei Starovoitov 	}
449*99a832a2SAlexei Starovoitov 
450*99a832a2SAlexei Starovoitov 	err = check_btf_func(env, attr, uattr);
451*99a832a2SAlexei Starovoitov 	if (err)
452*99a832a2SAlexei Starovoitov 		return err;
453*99a832a2SAlexei Starovoitov 
454*99a832a2SAlexei Starovoitov 	err = check_btf_line(env, attr, uattr);
455*99a832a2SAlexei Starovoitov 	if (err)
456*99a832a2SAlexei Starovoitov 		return err;
457*99a832a2SAlexei Starovoitov 
458*99a832a2SAlexei Starovoitov 	err = check_core_relo(env, attr, uattr);
459*99a832a2SAlexei Starovoitov 	if (err)
460*99a832a2SAlexei Starovoitov 		return err;
461*99a832a2SAlexei Starovoitov 
462*99a832a2SAlexei Starovoitov 	return 0;
463*99a832a2SAlexei Starovoitov }
464