xref: /linux/kernel/bpf/fixups.c (revision eb0d6d97c27c29cd7392c8fd74f46edf7dff7ec2)
1449f08faSAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0-only
2449f08faSAlexei Starovoitov /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3449f08faSAlexei Starovoitov #include <linux/bpf.h>
4449f08faSAlexei Starovoitov #include <linux/btf.h>
5449f08faSAlexei Starovoitov #include <linux/bpf_verifier.h>
6449f08faSAlexei Starovoitov #include <linux/filter.h>
7449f08faSAlexei Starovoitov #include <linux/vmalloc.h>
8449f08faSAlexei Starovoitov #include <linux/bsearch.h>
9449f08faSAlexei Starovoitov #include <linux/sort.h>
10449f08faSAlexei Starovoitov #include <linux/perf_event.h>
11449f08faSAlexei Starovoitov #include <net/xdp.h>
12449f08faSAlexei Starovoitov #include "disasm.h"
13449f08faSAlexei Starovoitov 
14449f08faSAlexei Starovoitov #define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
15449f08faSAlexei Starovoitov 
16449f08faSAlexei Starovoitov static bool is_cmpxchg_insn(const struct bpf_insn *insn)
17449f08faSAlexei Starovoitov {
18449f08faSAlexei Starovoitov 	return BPF_CLASS(insn->code) == BPF_STX &&
19449f08faSAlexei Starovoitov 	       BPF_MODE(insn->code) == BPF_ATOMIC &&
20449f08faSAlexei Starovoitov 	       insn->imm == BPF_CMPXCHG;
21449f08faSAlexei Starovoitov }
22449f08faSAlexei Starovoitov 
23449f08faSAlexei Starovoitov /* Return the regno defined by the insn, or -1. */
24449f08faSAlexei Starovoitov static int insn_def_regno(const struct bpf_insn *insn)
25449f08faSAlexei Starovoitov {
26449f08faSAlexei Starovoitov 	switch (BPF_CLASS(insn->code)) {
27449f08faSAlexei Starovoitov 	case BPF_JMP:
28449f08faSAlexei Starovoitov 	case BPF_JMP32:
29449f08faSAlexei Starovoitov 	case BPF_ST:
30449f08faSAlexei Starovoitov 		return -1;
31449f08faSAlexei Starovoitov 	case BPF_STX:
32449f08faSAlexei Starovoitov 		if (BPF_MODE(insn->code) == BPF_ATOMIC ||
33449f08faSAlexei Starovoitov 		    BPF_MODE(insn->code) == BPF_PROBE_ATOMIC) {
34449f08faSAlexei Starovoitov 			if (insn->imm == BPF_CMPXCHG)
35449f08faSAlexei Starovoitov 				return BPF_REG_0;
36449f08faSAlexei Starovoitov 			else if (insn->imm == BPF_LOAD_ACQ)
37449f08faSAlexei Starovoitov 				return insn->dst_reg;
38449f08faSAlexei Starovoitov 			else if (insn->imm & BPF_FETCH)
39449f08faSAlexei Starovoitov 				return insn->src_reg;
40449f08faSAlexei Starovoitov 		}
41449f08faSAlexei Starovoitov 		return -1;
42449f08faSAlexei Starovoitov 	default:
43449f08faSAlexei Starovoitov 		return insn->dst_reg;
44449f08faSAlexei Starovoitov 	}
45449f08faSAlexei Starovoitov }
46449f08faSAlexei Starovoitov 
47449f08faSAlexei Starovoitov /* Return TRUE if INSN has defined any 32-bit value explicitly. */
48449f08faSAlexei Starovoitov static bool insn_has_def32(struct bpf_insn *insn)
49449f08faSAlexei Starovoitov {
50449f08faSAlexei Starovoitov 	int dst_reg = insn_def_regno(insn);
51449f08faSAlexei Starovoitov 
52449f08faSAlexei Starovoitov 	if (dst_reg == -1)
53449f08faSAlexei Starovoitov 		return false;
54449f08faSAlexei Starovoitov 
55449f08faSAlexei Starovoitov 	return !bpf_is_reg64(insn, dst_reg, NULL, DST_OP);
56449f08faSAlexei Starovoitov }
57449f08faSAlexei Starovoitov 
58449f08faSAlexei Starovoitov static int kfunc_desc_cmp_by_imm_off(const void *a, const void *b)
59449f08faSAlexei Starovoitov {
60449f08faSAlexei Starovoitov 	const struct bpf_kfunc_desc *d0 = a;
61449f08faSAlexei Starovoitov 	const struct bpf_kfunc_desc *d1 = b;
62449f08faSAlexei Starovoitov 
63449f08faSAlexei Starovoitov 	if (d0->imm != d1->imm)
64449f08faSAlexei Starovoitov 		return d0->imm < d1->imm ? -1 : 1;
65449f08faSAlexei Starovoitov 	if (d0->offset != d1->offset)
66449f08faSAlexei Starovoitov 		return d0->offset < d1->offset ? -1 : 1;
67449f08faSAlexei Starovoitov 	return 0;
68449f08faSAlexei Starovoitov }
69449f08faSAlexei Starovoitov 
70449f08faSAlexei Starovoitov const struct btf_func_model *
71449f08faSAlexei Starovoitov bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
72449f08faSAlexei Starovoitov 			 const struct bpf_insn *insn)
73449f08faSAlexei Starovoitov {
74449f08faSAlexei Starovoitov 	const struct bpf_kfunc_desc desc = {
75449f08faSAlexei Starovoitov 		.imm = insn->imm,
76449f08faSAlexei Starovoitov 		.offset = insn->off,
77449f08faSAlexei Starovoitov 	};
78449f08faSAlexei Starovoitov 	const struct bpf_kfunc_desc *res;
79449f08faSAlexei Starovoitov 	struct bpf_kfunc_desc_tab *tab;
80449f08faSAlexei Starovoitov 
81449f08faSAlexei Starovoitov 	tab = prog->aux->kfunc_tab;
82449f08faSAlexei Starovoitov 	res = bsearch(&desc, tab->descs, tab->nr_descs,
83449f08faSAlexei Starovoitov 		      sizeof(tab->descs[0]), kfunc_desc_cmp_by_imm_off);
84449f08faSAlexei Starovoitov 
85449f08faSAlexei Starovoitov 	return res ? &res->func_model : NULL;
86449f08faSAlexei Starovoitov }
87449f08faSAlexei Starovoitov 
88449f08faSAlexei Starovoitov static int set_kfunc_desc_imm(struct bpf_verifier_env *env, struct bpf_kfunc_desc *desc)
89449f08faSAlexei Starovoitov {
90449f08faSAlexei Starovoitov 	unsigned long call_imm;
91449f08faSAlexei Starovoitov 
92449f08faSAlexei Starovoitov 	if (bpf_jit_supports_far_kfunc_call()) {
93449f08faSAlexei Starovoitov 		call_imm = desc->func_id;
94449f08faSAlexei Starovoitov 	} else {
95449f08faSAlexei Starovoitov 		call_imm = BPF_CALL_IMM(desc->addr);
96449f08faSAlexei Starovoitov 		/* Check whether the relative offset overflows desc->imm */
97449f08faSAlexei Starovoitov 		if ((unsigned long)(s32)call_imm != call_imm) {
98449f08faSAlexei Starovoitov 			verbose(env, "address of kernel func_id %u is out of range\n",
99449f08faSAlexei Starovoitov 				desc->func_id);
100449f08faSAlexei Starovoitov 			return -EINVAL;
101449f08faSAlexei Starovoitov 		}
102449f08faSAlexei Starovoitov 	}
103449f08faSAlexei Starovoitov 	desc->imm = call_imm;
104449f08faSAlexei Starovoitov 	return 0;
105449f08faSAlexei Starovoitov }
106449f08faSAlexei Starovoitov 
107449f08faSAlexei Starovoitov static int sort_kfunc_descs_by_imm_off(struct bpf_verifier_env *env)
108449f08faSAlexei Starovoitov {
109449f08faSAlexei Starovoitov 	struct bpf_kfunc_desc_tab *tab;
110449f08faSAlexei Starovoitov 	int i, err;
111449f08faSAlexei Starovoitov 
112449f08faSAlexei Starovoitov 	tab = env->prog->aux->kfunc_tab;
113449f08faSAlexei Starovoitov 	if (!tab)
114449f08faSAlexei Starovoitov 		return 0;
115449f08faSAlexei Starovoitov 
116449f08faSAlexei Starovoitov 	for (i = 0; i < tab->nr_descs; i++) {
117449f08faSAlexei Starovoitov 		err = set_kfunc_desc_imm(env, &tab->descs[i]);
118449f08faSAlexei Starovoitov 		if (err)
119449f08faSAlexei Starovoitov 			return err;
120449f08faSAlexei Starovoitov 	}
121449f08faSAlexei Starovoitov 
122449f08faSAlexei Starovoitov 	sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
123449f08faSAlexei Starovoitov 	     kfunc_desc_cmp_by_imm_off, NULL);
124449f08faSAlexei Starovoitov 	return 0;
125449f08faSAlexei Starovoitov }
126449f08faSAlexei Starovoitov 
127449f08faSAlexei Starovoitov static int add_kfunc_in_insns(struct bpf_verifier_env *env,
128449f08faSAlexei Starovoitov 			      struct bpf_insn *insn, int cnt)
129449f08faSAlexei Starovoitov {
130449f08faSAlexei Starovoitov 	int i, ret;
131449f08faSAlexei Starovoitov 
132449f08faSAlexei Starovoitov 	for (i = 0; i < cnt; i++, insn++) {
133449f08faSAlexei Starovoitov 		if (bpf_pseudo_kfunc_call(insn)) {
134449f08faSAlexei Starovoitov 			ret = bpf_add_kfunc_call(env, insn->imm, insn->off);
135449f08faSAlexei Starovoitov 			if (ret < 0)
136449f08faSAlexei Starovoitov 				return ret;
137449f08faSAlexei Starovoitov 		}
138449f08faSAlexei Starovoitov 	}
139449f08faSAlexei Starovoitov 	return 0;
140449f08faSAlexei Starovoitov }
141449f08faSAlexei Starovoitov 
142449f08faSAlexei Starovoitov #ifndef CONFIG_BPF_JIT_ALWAYS_ON
143449f08faSAlexei Starovoitov static int get_callee_stack_depth(struct bpf_verifier_env *env,
144449f08faSAlexei Starovoitov 				  const struct bpf_insn *insn, int idx)
145449f08faSAlexei Starovoitov {
146449f08faSAlexei Starovoitov 	int start = idx + insn->imm + 1, subprog;
147449f08faSAlexei Starovoitov 
148449f08faSAlexei Starovoitov 	subprog = bpf_find_subprog(env, start);
149449f08faSAlexei Starovoitov 	if (verifier_bug_if(subprog < 0, env, "get stack depth: no program at insn %d", start))
150449f08faSAlexei Starovoitov 		return -EFAULT;
151449f08faSAlexei Starovoitov 	return env->subprog_info[subprog].stack_depth;
152449f08faSAlexei Starovoitov }
153449f08faSAlexei Starovoitov #endif
154449f08faSAlexei Starovoitov 
155449f08faSAlexei Starovoitov /* single env->prog->insni[off] instruction was replaced with the range
156449f08faSAlexei Starovoitov  * insni[off, off + cnt).  Adjust corresponding insn_aux_data by copying
157449f08faSAlexei Starovoitov  * [0, off) and [off, end) to new locations, so the patched range stays zero
158449f08faSAlexei Starovoitov  */
159449f08faSAlexei Starovoitov static void adjust_insn_aux_data(struct bpf_verifier_env *env,
160449f08faSAlexei Starovoitov 				 struct bpf_prog *new_prog, u32 off, u32 cnt)
161449f08faSAlexei Starovoitov {
162449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *data = env->insn_aux_data;
163449f08faSAlexei Starovoitov 	struct bpf_insn *insn = new_prog->insnsi;
164449f08faSAlexei Starovoitov 	u32 old_seen = data[off].seen;
165449f08faSAlexei Starovoitov 	u32 prog_len;
166449f08faSAlexei Starovoitov 	int i;
167449f08faSAlexei Starovoitov 
168449f08faSAlexei Starovoitov 	/* aux info at OFF always needs adjustment, no matter fast path
169449f08faSAlexei Starovoitov 	 * (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the
170449f08faSAlexei Starovoitov 	 * original insn at old prog.
171449f08faSAlexei Starovoitov 	 */
172449f08faSAlexei Starovoitov 	data[off].zext_dst = insn_has_def32(insn + off + cnt - 1);
173449f08faSAlexei Starovoitov 
174449f08faSAlexei Starovoitov 	if (cnt == 1)
175449f08faSAlexei Starovoitov 		return;
176449f08faSAlexei Starovoitov 	prog_len = new_prog->len;
177449f08faSAlexei Starovoitov 
178449f08faSAlexei Starovoitov 	memmove(data + off + cnt - 1, data + off,
179449f08faSAlexei Starovoitov 		sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
180449f08faSAlexei Starovoitov 	memset(data + off, 0, sizeof(struct bpf_insn_aux_data) * (cnt - 1));
181449f08faSAlexei Starovoitov 	for (i = off; i < off + cnt - 1; i++) {
182449f08faSAlexei Starovoitov 		/* Expand insni[off]'s seen count to the patched range. */
183449f08faSAlexei Starovoitov 		data[i].seen = old_seen;
184449f08faSAlexei Starovoitov 		data[i].zext_dst = insn_has_def32(insn + i);
185449f08faSAlexei Starovoitov 	}
186*07ae6c13SXu Kuohai 
187*07ae6c13SXu Kuohai 	/*
188*07ae6c13SXu Kuohai 	 * The indirect_target flag of the original instruction was moved to the last of the
189*07ae6c13SXu Kuohai 	 * new instructions by the above memmove and memset, but the indirect jump target is
190*07ae6c13SXu Kuohai 	 * actually the first instruction, so move it back. This also matches with the behavior
191*07ae6c13SXu Kuohai 	 * of bpf_insn_array_adjust(), which preserves xlated_off to point to the first new
192*07ae6c13SXu Kuohai 	 * instruction.
193*07ae6c13SXu Kuohai 	 */
194*07ae6c13SXu Kuohai 	if (data[off + cnt - 1].indirect_target) {
195*07ae6c13SXu Kuohai 		data[off].indirect_target = 1;
196*07ae6c13SXu Kuohai 		data[off + cnt - 1].indirect_target = 0;
197*07ae6c13SXu Kuohai 	}
198449f08faSAlexei Starovoitov }
199449f08faSAlexei Starovoitov 
200449f08faSAlexei Starovoitov static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
201449f08faSAlexei Starovoitov {
202449f08faSAlexei Starovoitov 	int i;
203449f08faSAlexei Starovoitov 
204449f08faSAlexei Starovoitov 	if (len == 1)
205449f08faSAlexei Starovoitov 		return;
206449f08faSAlexei Starovoitov 	/* NOTE: fake 'exit' subprog should be updated as well. */
207449f08faSAlexei Starovoitov 	for (i = 0; i <= env->subprog_cnt; i++) {
208449f08faSAlexei Starovoitov 		if (env->subprog_info[i].start <= off)
209449f08faSAlexei Starovoitov 			continue;
210449f08faSAlexei Starovoitov 		env->subprog_info[i].start += len - 1;
211449f08faSAlexei Starovoitov 	}
212449f08faSAlexei Starovoitov }
213449f08faSAlexei Starovoitov 
214449f08faSAlexei Starovoitov static void adjust_insn_arrays(struct bpf_verifier_env *env, u32 off, u32 len)
215449f08faSAlexei Starovoitov {
216449f08faSAlexei Starovoitov 	int i;
217449f08faSAlexei Starovoitov 
218449f08faSAlexei Starovoitov 	if (len == 1)
219449f08faSAlexei Starovoitov 		return;
220449f08faSAlexei Starovoitov 
221449f08faSAlexei Starovoitov 	for (i = 0; i < env->insn_array_map_cnt; i++)
222449f08faSAlexei Starovoitov 		bpf_insn_array_adjust(env->insn_array_maps[i], off, len);
223449f08faSAlexei Starovoitov }
224449f08faSAlexei Starovoitov 
225449f08faSAlexei Starovoitov static void adjust_insn_arrays_after_remove(struct bpf_verifier_env *env, u32 off, u32 len)
226449f08faSAlexei Starovoitov {
227449f08faSAlexei Starovoitov 	int i;
228449f08faSAlexei Starovoitov 
229449f08faSAlexei Starovoitov 	for (i = 0; i < env->insn_array_map_cnt; i++)
230449f08faSAlexei Starovoitov 		bpf_insn_array_adjust_after_remove(env->insn_array_maps[i], off, len);
231449f08faSAlexei Starovoitov }
232449f08faSAlexei Starovoitov 
233449f08faSAlexei Starovoitov static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
234449f08faSAlexei Starovoitov {
235449f08faSAlexei Starovoitov 	struct bpf_jit_poke_descriptor *tab = prog->aux->poke_tab;
236449f08faSAlexei Starovoitov 	int i, sz = prog->aux->size_poke_tab;
237449f08faSAlexei Starovoitov 	struct bpf_jit_poke_descriptor *desc;
238449f08faSAlexei Starovoitov 
239449f08faSAlexei Starovoitov 	for (i = 0; i < sz; i++) {
240449f08faSAlexei Starovoitov 		desc = &tab[i];
241449f08faSAlexei Starovoitov 		if (desc->insn_idx <= off)
242449f08faSAlexei Starovoitov 			continue;
243449f08faSAlexei Starovoitov 		desc->insn_idx += len - 1;
244449f08faSAlexei Starovoitov 	}
245449f08faSAlexei Starovoitov }
246449f08faSAlexei Starovoitov 
247d3e94522SXu Kuohai struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
248449f08faSAlexei Starovoitov 				     const struct bpf_insn *patch, u32 len)
249449f08faSAlexei Starovoitov {
250449f08faSAlexei Starovoitov 	struct bpf_prog *new_prog;
251449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *new_data = NULL;
252449f08faSAlexei Starovoitov 
253449f08faSAlexei Starovoitov 	if (len > 1) {
254449f08faSAlexei Starovoitov 		new_data = vrealloc(env->insn_aux_data,
255449f08faSAlexei Starovoitov 				    array_size(env->prog->len + len - 1,
256449f08faSAlexei Starovoitov 					       sizeof(struct bpf_insn_aux_data)),
257449f08faSAlexei Starovoitov 				    GFP_KERNEL_ACCOUNT | __GFP_ZERO);
258449f08faSAlexei Starovoitov 		if (!new_data)
259449f08faSAlexei Starovoitov 			return NULL;
260449f08faSAlexei Starovoitov 
261449f08faSAlexei Starovoitov 		env->insn_aux_data = new_data;
262449f08faSAlexei Starovoitov 	}
263449f08faSAlexei Starovoitov 
264449f08faSAlexei Starovoitov 	new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
265449f08faSAlexei Starovoitov 	if (IS_ERR(new_prog)) {
266449f08faSAlexei Starovoitov 		if (PTR_ERR(new_prog) == -ERANGE)
267449f08faSAlexei Starovoitov 			verbose(env,
268449f08faSAlexei Starovoitov 				"insn %d cannot be patched due to 16-bit range\n",
269449f08faSAlexei Starovoitov 				env->insn_aux_data[off].orig_idx);
270449f08faSAlexei Starovoitov 		return NULL;
271449f08faSAlexei Starovoitov 	}
272449f08faSAlexei Starovoitov 	adjust_insn_aux_data(env, new_prog, off, len);
273449f08faSAlexei Starovoitov 	adjust_subprog_starts(env, off, len);
274449f08faSAlexei Starovoitov 	adjust_insn_arrays(env, off, len);
275449f08faSAlexei Starovoitov 	adjust_poke_descs(new_prog, off, len);
276449f08faSAlexei Starovoitov 	return new_prog;
277449f08faSAlexei Starovoitov }
278449f08faSAlexei Starovoitov 
279449f08faSAlexei Starovoitov /*
280449f08faSAlexei Starovoitov  * For all jmp insns in a given 'prog' that point to 'tgt_idx' insn adjust the
281449f08faSAlexei Starovoitov  * jump offset by 'delta'.
282449f08faSAlexei Starovoitov  */
283449f08faSAlexei Starovoitov static int adjust_jmp_off(struct bpf_prog *prog, u32 tgt_idx, u32 delta)
284449f08faSAlexei Starovoitov {
285449f08faSAlexei Starovoitov 	struct bpf_insn *insn = prog->insnsi;
286449f08faSAlexei Starovoitov 	u32 insn_cnt = prog->len, i;
287449f08faSAlexei Starovoitov 	s32 imm;
288449f08faSAlexei Starovoitov 	s16 off;
289449f08faSAlexei Starovoitov 
290449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++, insn++) {
291449f08faSAlexei Starovoitov 		u8 code = insn->code;
292449f08faSAlexei Starovoitov 
293449f08faSAlexei Starovoitov 		if (tgt_idx <= i && i < tgt_idx + delta)
294449f08faSAlexei Starovoitov 			continue;
295449f08faSAlexei Starovoitov 
296449f08faSAlexei Starovoitov 		if ((BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) ||
297449f08faSAlexei Starovoitov 		    BPF_OP(code) == BPF_CALL || BPF_OP(code) == BPF_EXIT)
298449f08faSAlexei Starovoitov 			continue;
299449f08faSAlexei Starovoitov 
300449f08faSAlexei Starovoitov 		if (insn->code == (BPF_JMP32 | BPF_JA)) {
301449f08faSAlexei Starovoitov 			if (i + 1 + insn->imm != tgt_idx)
302449f08faSAlexei Starovoitov 				continue;
303449f08faSAlexei Starovoitov 			if (check_add_overflow(insn->imm, delta, &imm))
304449f08faSAlexei Starovoitov 				return -ERANGE;
305449f08faSAlexei Starovoitov 			insn->imm = imm;
306449f08faSAlexei Starovoitov 		} else {
307449f08faSAlexei Starovoitov 			if (i + 1 + insn->off != tgt_idx)
308449f08faSAlexei Starovoitov 				continue;
309449f08faSAlexei Starovoitov 			if (check_add_overflow(insn->off, delta, &off))
310449f08faSAlexei Starovoitov 				return -ERANGE;
311449f08faSAlexei Starovoitov 			insn->off = off;
312449f08faSAlexei Starovoitov 		}
313449f08faSAlexei Starovoitov 	}
314449f08faSAlexei Starovoitov 	return 0;
315449f08faSAlexei Starovoitov }
316449f08faSAlexei Starovoitov 
317449f08faSAlexei Starovoitov static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
318449f08faSAlexei Starovoitov 					      u32 off, u32 cnt)
319449f08faSAlexei Starovoitov {
320449f08faSAlexei Starovoitov 	int i, j;
321449f08faSAlexei Starovoitov 
322449f08faSAlexei Starovoitov 	/* find first prog starting at or after off (first to remove) */
323449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++)
324449f08faSAlexei Starovoitov 		if (env->subprog_info[i].start >= off)
325449f08faSAlexei Starovoitov 			break;
326449f08faSAlexei Starovoitov 	/* find first prog starting at or after off + cnt (first to stay) */
327449f08faSAlexei Starovoitov 	for (j = i; j < env->subprog_cnt; j++)
328449f08faSAlexei Starovoitov 		if (env->subprog_info[j].start >= off + cnt)
329449f08faSAlexei Starovoitov 			break;
330449f08faSAlexei Starovoitov 	/* if j doesn't start exactly at off + cnt, we are just removing
331449f08faSAlexei Starovoitov 	 * the front of previous prog
332449f08faSAlexei Starovoitov 	 */
333449f08faSAlexei Starovoitov 	if (env->subprog_info[j].start != off + cnt)
334449f08faSAlexei Starovoitov 		j--;
335449f08faSAlexei Starovoitov 
336449f08faSAlexei Starovoitov 	if (j > i) {
337449f08faSAlexei Starovoitov 		struct bpf_prog_aux *aux = env->prog->aux;
338449f08faSAlexei Starovoitov 		int move;
339449f08faSAlexei Starovoitov 
340449f08faSAlexei Starovoitov 		/* move fake 'exit' subprog as well */
341449f08faSAlexei Starovoitov 		move = env->subprog_cnt + 1 - j;
342449f08faSAlexei Starovoitov 
343449f08faSAlexei Starovoitov 		memmove(env->subprog_info + i,
344449f08faSAlexei Starovoitov 			env->subprog_info + j,
345449f08faSAlexei Starovoitov 			sizeof(*env->subprog_info) * move);
346449f08faSAlexei Starovoitov 		env->subprog_cnt -= j - i;
347449f08faSAlexei Starovoitov 
348449f08faSAlexei Starovoitov 		/* remove func_info */
349449f08faSAlexei Starovoitov 		if (aux->func_info) {
350449f08faSAlexei Starovoitov 			move = aux->func_info_cnt - j;
351449f08faSAlexei Starovoitov 
352449f08faSAlexei Starovoitov 			memmove(aux->func_info + i,
353449f08faSAlexei Starovoitov 				aux->func_info + j,
354449f08faSAlexei Starovoitov 				sizeof(*aux->func_info) * move);
355449f08faSAlexei Starovoitov 			aux->func_info_cnt -= j - i;
356449f08faSAlexei Starovoitov 			/* func_info->insn_off is set after all code rewrites,
357449f08faSAlexei Starovoitov 			 * in adjust_btf_func() - no need to adjust
358449f08faSAlexei Starovoitov 			 */
359449f08faSAlexei Starovoitov 		}
360449f08faSAlexei Starovoitov 	} else {
361449f08faSAlexei Starovoitov 		/* convert i from "first prog to remove" to "first to adjust" */
362449f08faSAlexei Starovoitov 		if (env->subprog_info[i].start == off)
363449f08faSAlexei Starovoitov 			i++;
364449f08faSAlexei Starovoitov 	}
365449f08faSAlexei Starovoitov 
366449f08faSAlexei Starovoitov 	/* update fake 'exit' subprog as well */
367449f08faSAlexei Starovoitov 	for (; i <= env->subprog_cnt; i++)
368449f08faSAlexei Starovoitov 		env->subprog_info[i].start -= cnt;
369449f08faSAlexei Starovoitov 
370449f08faSAlexei Starovoitov 	return 0;
371449f08faSAlexei Starovoitov }
372449f08faSAlexei Starovoitov 
373449f08faSAlexei Starovoitov static int bpf_adj_linfo_after_remove(struct bpf_verifier_env *env, u32 off,
374449f08faSAlexei Starovoitov 				      u32 cnt)
375449f08faSAlexei Starovoitov {
376449f08faSAlexei Starovoitov 	struct bpf_prog *prog = env->prog;
377449f08faSAlexei Starovoitov 	u32 i, l_off, l_cnt, nr_linfo;
378449f08faSAlexei Starovoitov 	struct bpf_line_info *linfo;
379449f08faSAlexei Starovoitov 
380449f08faSAlexei Starovoitov 	nr_linfo = prog->aux->nr_linfo;
381449f08faSAlexei Starovoitov 	if (!nr_linfo)
382449f08faSAlexei Starovoitov 		return 0;
383449f08faSAlexei Starovoitov 
384449f08faSAlexei Starovoitov 	linfo = prog->aux->linfo;
385449f08faSAlexei Starovoitov 
386449f08faSAlexei Starovoitov 	/* find first line info to remove, count lines to be removed */
387449f08faSAlexei Starovoitov 	for (i = 0; i < nr_linfo; i++)
388449f08faSAlexei Starovoitov 		if (linfo[i].insn_off >= off)
389449f08faSAlexei Starovoitov 			break;
390449f08faSAlexei Starovoitov 
391449f08faSAlexei Starovoitov 	l_off = i;
392449f08faSAlexei Starovoitov 	l_cnt = 0;
393449f08faSAlexei Starovoitov 	for (; i < nr_linfo; i++)
394449f08faSAlexei Starovoitov 		if (linfo[i].insn_off < off + cnt)
395449f08faSAlexei Starovoitov 			l_cnt++;
396449f08faSAlexei Starovoitov 		else
397449f08faSAlexei Starovoitov 			break;
398449f08faSAlexei Starovoitov 
399449f08faSAlexei Starovoitov 	/* First live insn doesn't match first live linfo, it needs to "inherit"
400449f08faSAlexei Starovoitov 	 * last removed linfo.  prog is already modified, so prog->len == off
401449f08faSAlexei Starovoitov 	 * means no live instructions after (tail of the program was removed).
402449f08faSAlexei Starovoitov 	 */
403449f08faSAlexei Starovoitov 	if (prog->len != off && l_cnt &&
404449f08faSAlexei Starovoitov 	    (i == nr_linfo || linfo[i].insn_off != off + cnt)) {
405449f08faSAlexei Starovoitov 		l_cnt--;
406449f08faSAlexei Starovoitov 		linfo[--i].insn_off = off + cnt;
407449f08faSAlexei Starovoitov 	}
408449f08faSAlexei Starovoitov 
409449f08faSAlexei Starovoitov 	/* remove the line info which refer to the removed instructions */
410449f08faSAlexei Starovoitov 	if (l_cnt) {
411449f08faSAlexei Starovoitov 		memmove(linfo + l_off, linfo + i,
412449f08faSAlexei Starovoitov 			sizeof(*linfo) * (nr_linfo - i));
413449f08faSAlexei Starovoitov 
414449f08faSAlexei Starovoitov 		prog->aux->nr_linfo -= l_cnt;
415449f08faSAlexei Starovoitov 		nr_linfo = prog->aux->nr_linfo;
416449f08faSAlexei Starovoitov 	}
417449f08faSAlexei Starovoitov 
418449f08faSAlexei Starovoitov 	/* pull all linfo[i].insn_off >= off + cnt in by cnt */
419449f08faSAlexei Starovoitov 	for (i = l_off; i < nr_linfo; i++)
420449f08faSAlexei Starovoitov 		linfo[i].insn_off -= cnt;
421449f08faSAlexei Starovoitov 
422449f08faSAlexei Starovoitov 	/* fix up all subprogs (incl. 'exit') which start >= off */
423449f08faSAlexei Starovoitov 	for (i = 0; i <= env->subprog_cnt; i++)
424449f08faSAlexei Starovoitov 		if (env->subprog_info[i].linfo_idx > l_off) {
425449f08faSAlexei Starovoitov 			/* program may have started in the removed region but
426449f08faSAlexei Starovoitov 			 * may not be fully removed
427449f08faSAlexei Starovoitov 			 */
428449f08faSAlexei Starovoitov 			if (env->subprog_info[i].linfo_idx >= l_off + l_cnt)
429449f08faSAlexei Starovoitov 				env->subprog_info[i].linfo_idx -= l_cnt;
430449f08faSAlexei Starovoitov 			else
431449f08faSAlexei Starovoitov 				env->subprog_info[i].linfo_idx = l_off;
432449f08faSAlexei Starovoitov 		}
433449f08faSAlexei Starovoitov 
434449f08faSAlexei Starovoitov 	return 0;
435449f08faSAlexei Starovoitov }
436449f08faSAlexei Starovoitov 
437449f08faSAlexei Starovoitov /*
438449f08faSAlexei Starovoitov  * Clean up dynamically allocated fields of aux data for instructions [start, ...]
439449f08faSAlexei Starovoitov  */
440449f08faSAlexei Starovoitov void bpf_clear_insn_aux_data(struct bpf_verifier_env *env, int start, int len)
441449f08faSAlexei Starovoitov {
442449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
443449f08faSAlexei Starovoitov 	struct bpf_insn *insns = env->prog->insnsi;
444449f08faSAlexei Starovoitov 	int end = start + len;
445449f08faSAlexei Starovoitov 	int i;
446449f08faSAlexei Starovoitov 
447449f08faSAlexei Starovoitov 	for (i = start; i < end; i++) {
448449f08faSAlexei Starovoitov 		if (aux_data[i].jt) {
449449f08faSAlexei Starovoitov 			kvfree(aux_data[i].jt);
450449f08faSAlexei Starovoitov 			aux_data[i].jt = NULL;
451449f08faSAlexei Starovoitov 		}
452449f08faSAlexei Starovoitov 
453449f08faSAlexei Starovoitov 		if (bpf_is_ldimm64(&insns[i]))
454449f08faSAlexei Starovoitov 			i++;
455449f08faSAlexei Starovoitov 	}
456449f08faSAlexei Starovoitov }
457449f08faSAlexei Starovoitov 
458449f08faSAlexei Starovoitov static int verifier_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
459449f08faSAlexei Starovoitov {
460449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
461449f08faSAlexei Starovoitov 	unsigned int orig_prog_len = env->prog->len;
462449f08faSAlexei Starovoitov 	int err;
463449f08faSAlexei Starovoitov 
464449f08faSAlexei Starovoitov 	if (bpf_prog_is_offloaded(env->prog->aux))
465449f08faSAlexei Starovoitov 		bpf_prog_offload_remove_insns(env, off, cnt);
466449f08faSAlexei Starovoitov 
467449f08faSAlexei Starovoitov 	/* Should be called before bpf_remove_insns, as it uses prog->insnsi */
468449f08faSAlexei Starovoitov 	bpf_clear_insn_aux_data(env, off, cnt);
469449f08faSAlexei Starovoitov 
470449f08faSAlexei Starovoitov 	err = bpf_remove_insns(env->prog, off, cnt);
471449f08faSAlexei Starovoitov 	if (err)
472449f08faSAlexei Starovoitov 		return err;
473449f08faSAlexei Starovoitov 
474449f08faSAlexei Starovoitov 	err = adjust_subprog_starts_after_remove(env, off, cnt);
475449f08faSAlexei Starovoitov 	if (err)
476449f08faSAlexei Starovoitov 		return err;
477449f08faSAlexei Starovoitov 
478449f08faSAlexei Starovoitov 	err = bpf_adj_linfo_after_remove(env, off, cnt);
479449f08faSAlexei Starovoitov 	if (err)
480449f08faSAlexei Starovoitov 		return err;
481449f08faSAlexei Starovoitov 
482449f08faSAlexei Starovoitov 	adjust_insn_arrays_after_remove(env, off, cnt);
483449f08faSAlexei Starovoitov 
484449f08faSAlexei Starovoitov 	memmove(aux_data + off,	aux_data + off + cnt,
485449f08faSAlexei Starovoitov 		sizeof(*aux_data) * (orig_prog_len - off - cnt));
486449f08faSAlexei Starovoitov 
487449f08faSAlexei Starovoitov 	return 0;
488449f08faSAlexei Starovoitov }
489449f08faSAlexei Starovoitov 
490449f08faSAlexei Starovoitov static const struct bpf_insn NOP = BPF_JMP_IMM(BPF_JA, 0, 0, 0);
491449f08faSAlexei Starovoitov static const struct bpf_insn MAY_GOTO_0 = BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 0, 0);
492449f08faSAlexei Starovoitov 
493449f08faSAlexei Starovoitov bool bpf_insn_is_cond_jump(u8 code)
494449f08faSAlexei Starovoitov {
495449f08faSAlexei Starovoitov 	u8 op;
496449f08faSAlexei Starovoitov 
497449f08faSAlexei Starovoitov 	op = BPF_OP(code);
498449f08faSAlexei Starovoitov 	if (BPF_CLASS(code) == BPF_JMP32)
499449f08faSAlexei Starovoitov 		return op != BPF_JA;
500449f08faSAlexei Starovoitov 
501449f08faSAlexei Starovoitov 	if (BPF_CLASS(code) != BPF_JMP)
502449f08faSAlexei Starovoitov 		return false;
503449f08faSAlexei Starovoitov 
504449f08faSAlexei Starovoitov 	return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL;
505449f08faSAlexei Starovoitov }
506449f08faSAlexei Starovoitov 
507449f08faSAlexei Starovoitov void bpf_opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env)
508449f08faSAlexei Starovoitov {
509449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
510449f08faSAlexei Starovoitov 	struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0);
511449f08faSAlexei Starovoitov 	struct bpf_insn *insn = env->prog->insnsi;
512449f08faSAlexei Starovoitov 	const int insn_cnt = env->prog->len;
513449f08faSAlexei Starovoitov 	int i;
514449f08faSAlexei Starovoitov 
515449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++, insn++) {
516449f08faSAlexei Starovoitov 		if (!bpf_insn_is_cond_jump(insn->code))
517449f08faSAlexei Starovoitov 			continue;
518449f08faSAlexei Starovoitov 
519449f08faSAlexei Starovoitov 		if (!aux_data[i + 1].seen)
520449f08faSAlexei Starovoitov 			ja.off = insn->off;
521449f08faSAlexei Starovoitov 		else if (!aux_data[i + 1 + insn->off].seen)
522449f08faSAlexei Starovoitov 			ja.off = 0;
523449f08faSAlexei Starovoitov 		else
524449f08faSAlexei Starovoitov 			continue;
525449f08faSAlexei Starovoitov 
526449f08faSAlexei Starovoitov 		if (bpf_prog_is_offloaded(env->prog->aux))
527449f08faSAlexei Starovoitov 			bpf_prog_offload_replace_insn(env, i, &ja);
528449f08faSAlexei Starovoitov 
529449f08faSAlexei Starovoitov 		memcpy(insn, &ja, sizeof(ja));
530449f08faSAlexei Starovoitov 	}
531449f08faSAlexei Starovoitov }
532449f08faSAlexei Starovoitov 
533449f08faSAlexei Starovoitov int bpf_opt_remove_dead_code(struct bpf_verifier_env *env)
534449f08faSAlexei Starovoitov {
535449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
536449f08faSAlexei Starovoitov 	int insn_cnt = env->prog->len;
537449f08faSAlexei Starovoitov 	int i, err;
538449f08faSAlexei Starovoitov 
539449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++) {
540449f08faSAlexei Starovoitov 		int j;
541449f08faSAlexei Starovoitov 
542449f08faSAlexei Starovoitov 		j = 0;
543449f08faSAlexei Starovoitov 		while (i + j < insn_cnt && !aux_data[i + j].seen)
544449f08faSAlexei Starovoitov 			j++;
545449f08faSAlexei Starovoitov 		if (!j)
546449f08faSAlexei Starovoitov 			continue;
547449f08faSAlexei Starovoitov 
548449f08faSAlexei Starovoitov 		err = verifier_remove_insns(env, i, j);
549449f08faSAlexei Starovoitov 		if (err)
550449f08faSAlexei Starovoitov 			return err;
551449f08faSAlexei Starovoitov 		insn_cnt = env->prog->len;
552449f08faSAlexei Starovoitov 	}
553449f08faSAlexei Starovoitov 
554449f08faSAlexei Starovoitov 	return 0;
555449f08faSAlexei Starovoitov }
556449f08faSAlexei Starovoitov 
557449f08faSAlexei Starovoitov int bpf_opt_remove_nops(struct bpf_verifier_env *env)
558449f08faSAlexei Starovoitov {
559449f08faSAlexei Starovoitov 	struct bpf_insn *insn = env->prog->insnsi;
560449f08faSAlexei Starovoitov 	int insn_cnt = env->prog->len;
561449f08faSAlexei Starovoitov 	bool is_may_goto_0, is_ja;
562449f08faSAlexei Starovoitov 	int i, err;
563449f08faSAlexei Starovoitov 
564449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++) {
565449f08faSAlexei Starovoitov 		is_may_goto_0 = !memcmp(&insn[i], &MAY_GOTO_0, sizeof(MAY_GOTO_0));
566449f08faSAlexei Starovoitov 		is_ja = !memcmp(&insn[i], &NOP, sizeof(NOP));
567449f08faSAlexei Starovoitov 
568449f08faSAlexei Starovoitov 		if (!is_may_goto_0 && !is_ja)
569449f08faSAlexei Starovoitov 			continue;
570449f08faSAlexei Starovoitov 
571449f08faSAlexei Starovoitov 		err = verifier_remove_insns(env, i, 1);
572449f08faSAlexei Starovoitov 		if (err)
573449f08faSAlexei Starovoitov 			return err;
574449f08faSAlexei Starovoitov 		insn_cnt--;
575449f08faSAlexei Starovoitov 		/* Go back one insn to catch may_goto +1; may_goto +0 sequence */
576449f08faSAlexei Starovoitov 		i -= (is_may_goto_0 && i > 0) ? 2 : 1;
577449f08faSAlexei Starovoitov 	}
578449f08faSAlexei Starovoitov 
579449f08faSAlexei Starovoitov 	return 0;
580449f08faSAlexei Starovoitov }
581449f08faSAlexei Starovoitov 
582449f08faSAlexei Starovoitov int bpf_opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
583449f08faSAlexei Starovoitov 					 const union bpf_attr *attr)
584449f08faSAlexei Starovoitov {
585449f08faSAlexei Starovoitov 	struct bpf_insn *patch;
586449f08faSAlexei Starovoitov 	/* use env->insn_buf as two independent buffers */
587449f08faSAlexei Starovoitov 	struct bpf_insn *zext_patch = env->insn_buf;
588449f08faSAlexei Starovoitov 	struct bpf_insn *rnd_hi32_patch = &env->insn_buf[2];
589449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux = env->insn_aux_data;
590449f08faSAlexei Starovoitov 	int i, patch_len, delta = 0, len = env->prog->len;
591449f08faSAlexei Starovoitov 	struct bpf_insn *insns = env->prog->insnsi;
592449f08faSAlexei Starovoitov 	struct bpf_prog *new_prog;
593449f08faSAlexei Starovoitov 	bool rnd_hi32;
594449f08faSAlexei Starovoitov 
595449f08faSAlexei Starovoitov 	rnd_hi32 = attr->prog_flags & BPF_F_TEST_RND_HI32;
596449f08faSAlexei Starovoitov 	zext_patch[1] = BPF_ZEXT_REG(0);
597449f08faSAlexei Starovoitov 	rnd_hi32_patch[1] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, 0);
598449f08faSAlexei Starovoitov 	rnd_hi32_patch[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
599449f08faSAlexei Starovoitov 	rnd_hi32_patch[3] = BPF_ALU64_REG(BPF_OR, 0, BPF_REG_AX);
600449f08faSAlexei Starovoitov 	for (i = 0; i < len; i++) {
601449f08faSAlexei Starovoitov 		int adj_idx = i + delta;
602449f08faSAlexei Starovoitov 		struct bpf_insn insn;
603449f08faSAlexei Starovoitov 		int load_reg;
604449f08faSAlexei Starovoitov 
605449f08faSAlexei Starovoitov 		insn = insns[adj_idx];
606449f08faSAlexei Starovoitov 		load_reg = insn_def_regno(&insn);
607449f08faSAlexei Starovoitov 		if (!aux[adj_idx].zext_dst) {
608449f08faSAlexei Starovoitov 			u8 code, class;
609449f08faSAlexei Starovoitov 			u32 imm_rnd;
610449f08faSAlexei Starovoitov 
611449f08faSAlexei Starovoitov 			if (!rnd_hi32)
612449f08faSAlexei Starovoitov 				continue;
613449f08faSAlexei Starovoitov 
614449f08faSAlexei Starovoitov 			code = insn.code;
615449f08faSAlexei Starovoitov 			class = BPF_CLASS(code);
616449f08faSAlexei Starovoitov 			if (load_reg == -1)
617449f08faSAlexei Starovoitov 				continue;
618449f08faSAlexei Starovoitov 
619449f08faSAlexei Starovoitov 			/* NOTE: arg "reg" (the fourth one) is only used for
620449f08faSAlexei Starovoitov 			 *       BPF_STX + SRC_OP, so it is safe to pass NULL
621449f08faSAlexei Starovoitov 			 *       here.
622449f08faSAlexei Starovoitov 			 */
623449f08faSAlexei Starovoitov 			if (bpf_is_reg64(&insn, load_reg, NULL, DST_OP)) {
624449f08faSAlexei Starovoitov 				if (class == BPF_LD &&
625449f08faSAlexei Starovoitov 				    BPF_MODE(code) == BPF_IMM)
626449f08faSAlexei Starovoitov 					i++;
627449f08faSAlexei Starovoitov 				continue;
628449f08faSAlexei Starovoitov 			}
629449f08faSAlexei Starovoitov 
630449f08faSAlexei Starovoitov 			/* ctx load could be transformed into wider load. */
631449f08faSAlexei Starovoitov 			if (class == BPF_LDX &&
632449f08faSAlexei Starovoitov 			    aux[adj_idx].ptr_type == PTR_TO_CTX)
633449f08faSAlexei Starovoitov 				continue;
634449f08faSAlexei Starovoitov 
635449f08faSAlexei Starovoitov 			imm_rnd = get_random_u32();
636449f08faSAlexei Starovoitov 			rnd_hi32_patch[0] = insn;
637449f08faSAlexei Starovoitov 			rnd_hi32_patch[1].imm = imm_rnd;
638449f08faSAlexei Starovoitov 			rnd_hi32_patch[3].dst_reg = load_reg;
639449f08faSAlexei Starovoitov 			patch = rnd_hi32_patch;
640449f08faSAlexei Starovoitov 			patch_len = 4;
641449f08faSAlexei Starovoitov 			goto apply_patch_buffer;
642449f08faSAlexei Starovoitov 		}
643449f08faSAlexei Starovoitov 
644449f08faSAlexei Starovoitov 		/* Add in an zero-extend instruction if a) the JIT has requested
645449f08faSAlexei Starovoitov 		 * it or b) it's a CMPXCHG.
646449f08faSAlexei Starovoitov 		 *
647449f08faSAlexei Starovoitov 		 * The latter is because: BPF_CMPXCHG always loads a value into
648449f08faSAlexei Starovoitov 		 * R0, therefore always zero-extends. However some archs'
649449f08faSAlexei Starovoitov 		 * equivalent instruction only does this load when the
650449f08faSAlexei Starovoitov 		 * comparison is successful. This detail of CMPXCHG is
651449f08faSAlexei Starovoitov 		 * orthogonal to the general zero-extension behaviour of the
652449f08faSAlexei Starovoitov 		 * CPU, so it's treated independently of bpf_jit_needs_zext.
653449f08faSAlexei Starovoitov 		 */
654449f08faSAlexei Starovoitov 		if (!bpf_jit_needs_zext() && !is_cmpxchg_insn(&insn))
655449f08faSAlexei Starovoitov 			continue;
656449f08faSAlexei Starovoitov 
657449f08faSAlexei Starovoitov 		/* Zero-extension is done by the caller. */
658449f08faSAlexei Starovoitov 		if (bpf_pseudo_kfunc_call(&insn))
659449f08faSAlexei Starovoitov 			continue;
660449f08faSAlexei Starovoitov 
661449f08faSAlexei Starovoitov 		if (verifier_bug_if(load_reg == -1, env,
662449f08faSAlexei Starovoitov 				    "zext_dst is set, but no reg is defined"))
663449f08faSAlexei Starovoitov 			return -EFAULT;
664449f08faSAlexei Starovoitov 
665449f08faSAlexei Starovoitov 		zext_patch[0] = insn;
666449f08faSAlexei Starovoitov 		zext_patch[1].dst_reg = load_reg;
667449f08faSAlexei Starovoitov 		zext_patch[1].src_reg = load_reg;
668449f08faSAlexei Starovoitov 		patch = zext_patch;
669449f08faSAlexei Starovoitov 		patch_len = 2;
670449f08faSAlexei Starovoitov apply_patch_buffer:
671449f08faSAlexei Starovoitov 		new_prog = bpf_patch_insn_data(env, adj_idx, patch, patch_len);
672449f08faSAlexei Starovoitov 		if (!new_prog)
673449f08faSAlexei Starovoitov 			return -ENOMEM;
674449f08faSAlexei Starovoitov 		env->prog = new_prog;
675449f08faSAlexei Starovoitov 		insns = new_prog->insnsi;
676449f08faSAlexei Starovoitov 		aux = env->insn_aux_data;
677449f08faSAlexei Starovoitov 		delta += patch_len - 1;
678449f08faSAlexei Starovoitov 	}
679449f08faSAlexei Starovoitov 
680449f08faSAlexei Starovoitov 	return 0;
681449f08faSAlexei Starovoitov }
682449f08faSAlexei Starovoitov 
683449f08faSAlexei Starovoitov /* convert load instructions that access fields of a context type into a
684449f08faSAlexei Starovoitov  * sequence of instructions that access fields of the underlying structure:
685449f08faSAlexei Starovoitov  *     struct __sk_buff    -> struct sk_buff
686449f08faSAlexei Starovoitov  *     struct bpf_sock_ops -> struct sock
687449f08faSAlexei Starovoitov  */
688449f08faSAlexei Starovoitov int bpf_convert_ctx_accesses(struct bpf_verifier_env *env)
689449f08faSAlexei Starovoitov {
690449f08faSAlexei Starovoitov 	struct bpf_subprog_info *subprogs = env->subprog_info;
691449f08faSAlexei Starovoitov 	const struct bpf_verifier_ops *ops = env->ops;
692449f08faSAlexei Starovoitov 	int i, cnt, size, ctx_field_size, ret, delta = 0, epilogue_cnt = 0;
693449f08faSAlexei Starovoitov 	const int insn_cnt = env->prog->len;
694449f08faSAlexei Starovoitov 	struct bpf_insn *epilogue_buf = env->epilogue_buf;
695449f08faSAlexei Starovoitov 	struct bpf_insn *insn_buf = env->insn_buf;
696449f08faSAlexei Starovoitov 	struct bpf_insn *insn;
697449f08faSAlexei Starovoitov 	u32 target_size, size_default, off;
698449f08faSAlexei Starovoitov 	struct bpf_prog *new_prog;
699449f08faSAlexei Starovoitov 	enum bpf_access_type type;
700449f08faSAlexei Starovoitov 	bool is_narrower_load;
701449f08faSAlexei Starovoitov 	int epilogue_idx = 0;
702449f08faSAlexei Starovoitov 
703449f08faSAlexei Starovoitov 	if (ops->gen_epilogue) {
704449f08faSAlexei Starovoitov 		epilogue_cnt = ops->gen_epilogue(epilogue_buf, env->prog,
705449f08faSAlexei Starovoitov 						 -(subprogs[0].stack_depth + 8));
706449f08faSAlexei Starovoitov 		if (epilogue_cnt >= INSN_BUF_SIZE) {
707449f08faSAlexei Starovoitov 			verifier_bug(env, "epilogue is too long");
708449f08faSAlexei Starovoitov 			return -EFAULT;
709449f08faSAlexei Starovoitov 		} else if (epilogue_cnt) {
710449f08faSAlexei Starovoitov 			/* Save the ARG_PTR_TO_CTX for the epilogue to use */
711449f08faSAlexei Starovoitov 			cnt = 0;
712449f08faSAlexei Starovoitov 			subprogs[0].stack_depth += 8;
713449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_1,
714449f08faSAlexei Starovoitov 						      -subprogs[0].stack_depth);
715449f08faSAlexei Starovoitov 			insn_buf[cnt++] = env->prog->insnsi[0];
716449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
717449f08faSAlexei Starovoitov 			if (!new_prog)
718449f08faSAlexei Starovoitov 				return -ENOMEM;
719449f08faSAlexei Starovoitov 			env->prog = new_prog;
720449f08faSAlexei Starovoitov 			delta += cnt - 1;
721449f08faSAlexei Starovoitov 
722449f08faSAlexei Starovoitov 			ret = add_kfunc_in_insns(env, epilogue_buf, epilogue_cnt - 1);
723449f08faSAlexei Starovoitov 			if (ret < 0)
724449f08faSAlexei Starovoitov 				return ret;
725449f08faSAlexei Starovoitov 		}
726449f08faSAlexei Starovoitov 	}
727449f08faSAlexei Starovoitov 
728449f08faSAlexei Starovoitov 	if (ops->gen_prologue || env->seen_direct_write) {
729449f08faSAlexei Starovoitov 		if (!ops->gen_prologue) {
730449f08faSAlexei Starovoitov 			verifier_bug(env, "gen_prologue is null");
731449f08faSAlexei Starovoitov 			return -EFAULT;
732449f08faSAlexei Starovoitov 		}
733449f08faSAlexei Starovoitov 		cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
734449f08faSAlexei Starovoitov 					env->prog);
735449f08faSAlexei Starovoitov 		if (cnt >= INSN_BUF_SIZE) {
736449f08faSAlexei Starovoitov 			verifier_bug(env, "prologue is too long");
737449f08faSAlexei Starovoitov 			return -EFAULT;
738449f08faSAlexei Starovoitov 		} else if (cnt) {
739449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
740449f08faSAlexei Starovoitov 			if (!new_prog)
741449f08faSAlexei Starovoitov 				return -ENOMEM;
742449f08faSAlexei Starovoitov 
743449f08faSAlexei Starovoitov 			env->prog = new_prog;
744449f08faSAlexei Starovoitov 			delta += cnt - 1;
745449f08faSAlexei Starovoitov 
746449f08faSAlexei Starovoitov 			ret = add_kfunc_in_insns(env, insn_buf, cnt - 1);
747449f08faSAlexei Starovoitov 			if (ret < 0)
748449f08faSAlexei Starovoitov 				return ret;
749449f08faSAlexei Starovoitov 		}
750449f08faSAlexei Starovoitov 	}
751449f08faSAlexei Starovoitov 
752449f08faSAlexei Starovoitov 	if (delta)
753449f08faSAlexei Starovoitov 		WARN_ON(adjust_jmp_off(env->prog, 0, delta));
754449f08faSAlexei Starovoitov 
755449f08faSAlexei Starovoitov 	if (bpf_prog_is_offloaded(env->prog->aux))
756449f08faSAlexei Starovoitov 		return 0;
757449f08faSAlexei Starovoitov 
758449f08faSAlexei Starovoitov 	insn = env->prog->insnsi + delta;
759449f08faSAlexei Starovoitov 
760449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++, insn++) {
761449f08faSAlexei Starovoitov 		bpf_convert_ctx_access_t convert_ctx_access;
762449f08faSAlexei Starovoitov 		u8 mode;
763449f08faSAlexei Starovoitov 
764449f08faSAlexei Starovoitov 		if (env->insn_aux_data[i + delta].nospec) {
765449f08faSAlexei Starovoitov 			WARN_ON_ONCE(env->insn_aux_data[i + delta].alu_state);
766449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
767449f08faSAlexei Starovoitov 
768449f08faSAlexei Starovoitov 			*patch++ = BPF_ST_NOSPEC();
769449f08faSAlexei Starovoitov 			*patch++ = *insn;
770449f08faSAlexei Starovoitov 			cnt = patch - insn_buf;
771449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
772449f08faSAlexei Starovoitov 			if (!new_prog)
773449f08faSAlexei Starovoitov 				return -ENOMEM;
774449f08faSAlexei Starovoitov 
775449f08faSAlexei Starovoitov 			delta    += cnt - 1;
776449f08faSAlexei Starovoitov 			env->prog = new_prog;
777449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
778449f08faSAlexei Starovoitov 			/* This can not be easily merged with the
779449f08faSAlexei Starovoitov 			 * nospec_result-case, because an insn may require a
780449f08faSAlexei Starovoitov 			 * nospec before and after itself. Therefore also do not
781449f08faSAlexei Starovoitov 			 * 'continue' here but potentially apply further
782449f08faSAlexei Starovoitov 			 * patching to insn. *insn should equal patch[1] now.
783449f08faSAlexei Starovoitov 			 */
784449f08faSAlexei Starovoitov 		}
785449f08faSAlexei Starovoitov 
786449f08faSAlexei Starovoitov 		if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) ||
787449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEM | BPF_H) ||
788449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
789449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEM | BPF_DW) ||
790449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEMSX | BPF_B) ||
791449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEMSX | BPF_H) ||
792449f08faSAlexei Starovoitov 		    insn->code == (BPF_LDX | BPF_MEMSX | BPF_W)) {
793449f08faSAlexei Starovoitov 			type = BPF_READ;
794449f08faSAlexei Starovoitov 		} else if (insn->code == (BPF_STX | BPF_MEM | BPF_B) ||
795449f08faSAlexei Starovoitov 			   insn->code == (BPF_STX | BPF_MEM | BPF_H) ||
796449f08faSAlexei Starovoitov 			   insn->code == (BPF_STX | BPF_MEM | BPF_W) ||
797449f08faSAlexei Starovoitov 			   insn->code == (BPF_STX | BPF_MEM | BPF_DW) ||
798449f08faSAlexei Starovoitov 			   insn->code == (BPF_ST | BPF_MEM | BPF_B) ||
799449f08faSAlexei Starovoitov 			   insn->code == (BPF_ST | BPF_MEM | BPF_H) ||
800449f08faSAlexei Starovoitov 			   insn->code == (BPF_ST | BPF_MEM | BPF_W) ||
801449f08faSAlexei Starovoitov 			   insn->code == (BPF_ST | BPF_MEM | BPF_DW)) {
802449f08faSAlexei Starovoitov 			type = BPF_WRITE;
803449f08faSAlexei Starovoitov 		} else if ((insn->code == (BPF_STX | BPF_ATOMIC | BPF_B) ||
804449f08faSAlexei Starovoitov 			    insn->code == (BPF_STX | BPF_ATOMIC | BPF_H) ||
805449f08faSAlexei Starovoitov 			    insn->code == (BPF_STX | BPF_ATOMIC | BPF_W) ||
806449f08faSAlexei Starovoitov 			    insn->code == (BPF_STX | BPF_ATOMIC | BPF_DW)) &&
807449f08faSAlexei Starovoitov 			   env->insn_aux_data[i + delta].ptr_type == PTR_TO_ARENA) {
808449f08faSAlexei Starovoitov 			insn->code = BPF_STX | BPF_PROBE_ATOMIC | BPF_SIZE(insn->code);
809449f08faSAlexei Starovoitov 			env->prog->aux->num_exentries++;
810449f08faSAlexei Starovoitov 			continue;
811449f08faSAlexei Starovoitov 		} else if (insn->code == (BPF_JMP | BPF_EXIT) &&
812449f08faSAlexei Starovoitov 			   epilogue_cnt &&
813449f08faSAlexei Starovoitov 			   i + delta < subprogs[1].start) {
814449f08faSAlexei Starovoitov 			/* Generate epilogue for the main prog */
815449f08faSAlexei Starovoitov 			if (epilogue_idx) {
816449f08faSAlexei Starovoitov 				/* jump back to the earlier generated epilogue */
817449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_JMP32_A(epilogue_idx - i - delta - 1);
818449f08faSAlexei Starovoitov 				cnt = 1;
819449f08faSAlexei Starovoitov 			} else {
820449f08faSAlexei Starovoitov 				memcpy(insn_buf, epilogue_buf,
821449f08faSAlexei Starovoitov 				       epilogue_cnt * sizeof(*epilogue_buf));
822449f08faSAlexei Starovoitov 				cnt = epilogue_cnt;
823449f08faSAlexei Starovoitov 				/* epilogue_idx cannot be 0. It must have at
824449f08faSAlexei Starovoitov 				 * least one ctx ptr saving insn before the
825449f08faSAlexei Starovoitov 				 * epilogue.
826449f08faSAlexei Starovoitov 				 */
827449f08faSAlexei Starovoitov 				epilogue_idx = i + delta;
828449f08faSAlexei Starovoitov 			}
829449f08faSAlexei Starovoitov 			goto patch_insn_buf;
830449f08faSAlexei Starovoitov 		} else {
831449f08faSAlexei Starovoitov 			continue;
832449f08faSAlexei Starovoitov 		}
833449f08faSAlexei Starovoitov 
834449f08faSAlexei Starovoitov 		if (type == BPF_WRITE &&
835449f08faSAlexei Starovoitov 		    env->insn_aux_data[i + delta].nospec_result) {
836449f08faSAlexei Starovoitov 			/* nospec_result is only used to mitigate Spectre v4 and
837449f08faSAlexei Starovoitov 			 * to limit verification-time for Spectre v1.
838449f08faSAlexei Starovoitov 			 */
839449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
840449f08faSAlexei Starovoitov 
841449f08faSAlexei Starovoitov 			*patch++ = *insn;
842449f08faSAlexei Starovoitov 			*patch++ = BPF_ST_NOSPEC();
843449f08faSAlexei Starovoitov 			cnt = patch - insn_buf;
844449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
845449f08faSAlexei Starovoitov 			if (!new_prog)
846449f08faSAlexei Starovoitov 				return -ENOMEM;
847449f08faSAlexei Starovoitov 
848449f08faSAlexei Starovoitov 			delta    += cnt - 1;
849449f08faSAlexei Starovoitov 			env->prog = new_prog;
850449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
851449f08faSAlexei Starovoitov 			continue;
852449f08faSAlexei Starovoitov 		}
853449f08faSAlexei Starovoitov 
854449f08faSAlexei Starovoitov 		switch ((int)env->insn_aux_data[i + delta].ptr_type) {
855449f08faSAlexei Starovoitov 		case PTR_TO_CTX:
856449f08faSAlexei Starovoitov 			if (!ops->convert_ctx_access)
857449f08faSAlexei Starovoitov 				continue;
858449f08faSAlexei Starovoitov 			convert_ctx_access = ops->convert_ctx_access;
859449f08faSAlexei Starovoitov 			break;
860449f08faSAlexei Starovoitov 		case PTR_TO_SOCKET:
861449f08faSAlexei Starovoitov 		case PTR_TO_SOCK_COMMON:
862449f08faSAlexei Starovoitov 			convert_ctx_access = bpf_sock_convert_ctx_access;
863449f08faSAlexei Starovoitov 			break;
864449f08faSAlexei Starovoitov 		case PTR_TO_TCP_SOCK:
865449f08faSAlexei Starovoitov 			convert_ctx_access = bpf_tcp_sock_convert_ctx_access;
866449f08faSAlexei Starovoitov 			break;
867449f08faSAlexei Starovoitov 		case PTR_TO_XDP_SOCK:
868449f08faSAlexei Starovoitov 			convert_ctx_access = bpf_xdp_sock_convert_ctx_access;
869449f08faSAlexei Starovoitov 			break;
870449f08faSAlexei Starovoitov 		case PTR_TO_BTF_ID:
871449f08faSAlexei Starovoitov 		case PTR_TO_BTF_ID | PTR_UNTRUSTED:
872449f08faSAlexei Starovoitov 		/* PTR_TO_BTF_ID | MEM_ALLOC always has a valid lifetime, unlike
873449f08faSAlexei Starovoitov 		 * PTR_TO_BTF_ID, and an active ref_obj_id, but the same cannot
874449f08faSAlexei Starovoitov 		 * be said once it is marked PTR_UNTRUSTED, hence we must handle
875449f08faSAlexei Starovoitov 		 * any faults for loads into such types. BPF_WRITE is disallowed
876449f08faSAlexei Starovoitov 		 * for this case.
877449f08faSAlexei Starovoitov 		 */
878449f08faSAlexei Starovoitov 		case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED:
879449f08faSAlexei Starovoitov 		case PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED:
880449f08faSAlexei Starovoitov 			if (type == BPF_READ) {
881449f08faSAlexei Starovoitov 				if (BPF_MODE(insn->code) == BPF_MEM)
882449f08faSAlexei Starovoitov 					insn->code = BPF_LDX | BPF_PROBE_MEM |
883449f08faSAlexei Starovoitov 						     BPF_SIZE((insn)->code);
884449f08faSAlexei Starovoitov 				else
885449f08faSAlexei Starovoitov 					insn->code = BPF_LDX | BPF_PROBE_MEMSX |
886449f08faSAlexei Starovoitov 						     BPF_SIZE((insn)->code);
887449f08faSAlexei Starovoitov 				env->prog->aux->num_exentries++;
888449f08faSAlexei Starovoitov 			}
889449f08faSAlexei Starovoitov 			continue;
890449f08faSAlexei Starovoitov 		case PTR_TO_ARENA:
891449f08faSAlexei Starovoitov 			if (BPF_MODE(insn->code) == BPF_MEMSX) {
892449f08faSAlexei Starovoitov 				if (!bpf_jit_supports_insn(insn, true)) {
893449f08faSAlexei Starovoitov 					verbose(env, "sign extending loads from arena are not supported yet\n");
894449f08faSAlexei Starovoitov 					return -EOPNOTSUPP;
895449f08faSAlexei Starovoitov 				}
896449f08faSAlexei Starovoitov 				insn->code = BPF_CLASS(insn->code) | BPF_PROBE_MEM32SX | BPF_SIZE(insn->code);
897449f08faSAlexei Starovoitov 			} else {
898449f08faSAlexei Starovoitov 				insn->code = BPF_CLASS(insn->code) | BPF_PROBE_MEM32 | BPF_SIZE(insn->code);
899449f08faSAlexei Starovoitov 			}
900449f08faSAlexei Starovoitov 			env->prog->aux->num_exentries++;
901449f08faSAlexei Starovoitov 			continue;
902449f08faSAlexei Starovoitov 		default:
903449f08faSAlexei Starovoitov 			continue;
904449f08faSAlexei Starovoitov 		}
905449f08faSAlexei Starovoitov 
906449f08faSAlexei Starovoitov 		ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size;
907449f08faSAlexei Starovoitov 		size = BPF_LDST_BYTES(insn);
908449f08faSAlexei Starovoitov 		mode = BPF_MODE(insn->code);
909449f08faSAlexei Starovoitov 
910449f08faSAlexei Starovoitov 		/* If the read access is a narrower load of the field,
911449f08faSAlexei Starovoitov 		 * convert to a 4/8-byte load, to minimum program type specific
912449f08faSAlexei Starovoitov 		 * convert_ctx_access changes. If conversion is successful,
913449f08faSAlexei Starovoitov 		 * we will apply proper mask to the result.
914449f08faSAlexei Starovoitov 		 */
915449f08faSAlexei Starovoitov 		is_narrower_load = size < ctx_field_size;
916449f08faSAlexei Starovoitov 		size_default = bpf_ctx_off_adjust_machine(ctx_field_size);
917449f08faSAlexei Starovoitov 		off = insn->off;
918449f08faSAlexei Starovoitov 		if (is_narrower_load) {
919449f08faSAlexei Starovoitov 			u8 size_code;
920449f08faSAlexei Starovoitov 
921449f08faSAlexei Starovoitov 			if (type == BPF_WRITE) {
922449f08faSAlexei Starovoitov 				verifier_bug(env, "narrow ctx access misconfigured");
923449f08faSAlexei Starovoitov 				return -EFAULT;
924449f08faSAlexei Starovoitov 			}
925449f08faSAlexei Starovoitov 
926449f08faSAlexei Starovoitov 			size_code = BPF_H;
927449f08faSAlexei Starovoitov 			if (ctx_field_size == 4)
928449f08faSAlexei Starovoitov 				size_code = BPF_W;
929449f08faSAlexei Starovoitov 			else if (ctx_field_size == 8)
930449f08faSAlexei Starovoitov 				size_code = BPF_DW;
931449f08faSAlexei Starovoitov 
932449f08faSAlexei Starovoitov 			insn->off = off & ~(size_default - 1);
933449f08faSAlexei Starovoitov 			insn->code = BPF_LDX | BPF_MEM | size_code;
934449f08faSAlexei Starovoitov 		}
935449f08faSAlexei Starovoitov 
936449f08faSAlexei Starovoitov 		target_size = 0;
937449f08faSAlexei Starovoitov 		cnt = convert_ctx_access(type, insn, insn_buf, env->prog,
938449f08faSAlexei Starovoitov 					 &target_size);
939449f08faSAlexei Starovoitov 		if (cnt == 0 || cnt >= INSN_BUF_SIZE ||
940449f08faSAlexei Starovoitov 		    (ctx_field_size && !target_size)) {
941449f08faSAlexei Starovoitov 			verifier_bug(env, "error during ctx access conversion (%d)", cnt);
942449f08faSAlexei Starovoitov 			return -EFAULT;
943449f08faSAlexei Starovoitov 		}
944449f08faSAlexei Starovoitov 
945449f08faSAlexei Starovoitov 		if (is_narrower_load && size < target_size) {
946449f08faSAlexei Starovoitov 			u8 shift = bpf_ctx_narrow_access_offset(
947449f08faSAlexei Starovoitov 				off, size, size_default) * 8;
948449f08faSAlexei Starovoitov 			if (shift && cnt + 1 >= INSN_BUF_SIZE) {
949449f08faSAlexei Starovoitov 				verifier_bug(env, "narrow ctx load misconfigured");
950449f08faSAlexei Starovoitov 				return -EFAULT;
951449f08faSAlexei Starovoitov 			}
952449f08faSAlexei Starovoitov 			if (ctx_field_size <= 4) {
953449f08faSAlexei Starovoitov 				if (shift)
954449f08faSAlexei Starovoitov 					insn_buf[cnt++] = BPF_ALU32_IMM(BPF_RSH,
955449f08faSAlexei Starovoitov 									insn->dst_reg,
956449f08faSAlexei Starovoitov 									shift);
957449f08faSAlexei Starovoitov 				insn_buf[cnt++] = BPF_ALU32_IMM(BPF_AND, insn->dst_reg,
958449f08faSAlexei Starovoitov 								(1 << size * 8) - 1);
959449f08faSAlexei Starovoitov 			} else {
960449f08faSAlexei Starovoitov 				if (shift)
961449f08faSAlexei Starovoitov 					insn_buf[cnt++] = BPF_ALU64_IMM(BPF_RSH,
962449f08faSAlexei Starovoitov 									insn->dst_reg,
963449f08faSAlexei Starovoitov 									shift);
964449f08faSAlexei Starovoitov 				insn_buf[cnt++] = BPF_ALU32_IMM(BPF_AND, insn->dst_reg,
965449f08faSAlexei Starovoitov 								(1ULL << size * 8) - 1);
966449f08faSAlexei Starovoitov 			}
967449f08faSAlexei Starovoitov 		}
968449f08faSAlexei Starovoitov 		if (mode == BPF_MEMSX)
969449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_RAW_INSN(BPF_ALU64 | BPF_MOV | BPF_X,
970449f08faSAlexei Starovoitov 						       insn->dst_reg, insn->dst_reg,
971449f08faSAlexei Starovoitov 						       size * 8, 0);
972449f08faSAlexei Starovoitov 
973449f08faSAlexei Starovoitov patch_insn_buf:
974449f08faSAlexei Starovoitov 		new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
975449f08faSAlexei Starovoitov 		if (!new_prog)
976449f08faSAlexei Starovoitov 			return -ENOMEM;
977449f08faSAlexei Starovoitov 
978449f08faSAlexei Starovoitov 		delta += cnt - 1;
979449f08faSAlexei Starovoitov 
980449f08faSAlexei Starovoitov 		/* keep walking new program and skip insns we just inserted */
981449f08faSAlexei Starovoitov 		env->prog = new_prog;
982449f08faSAlexei Starovoitov 		insn      = new_prog->insnsi + i + delta;
983449f08faSAlexei Starovoitov 	}
984449f08faSAlexei Starovoitov 
985449f08faSAlexei Starovoitov 	return 0;
986449f08faSAlexei Starovoitov }
987449f08faSAlexei Starovoitov 
988d3e94522SXu Kuohai static u32 *bpf_dup_subprog_starts(struct bpf_verifier_env *env)
989d3e94522SXu Kuohai {
990d3e94522SXu Kuohai 	u32 *starts = NULL;
991d3e94522SXu Kuohai 
992d3e94522SXu Kuohai 	starts = kvmalloc_objs(u32, env->subprog_cnt, GFP_KERNEL_ACCOUNT);
993d3e94522SXu Kuohai 	if (starts) {
994d3e94522SXu Kuohai 		for (int i = 0; i < env->subprog_cnt; i++)
995d3e94522SXu Kuohai 			starts[i] = env->subprog_info[i].start;
996d3e94522SXu Kuohai 	}
997d3e94522SXu Kuohai 	return starts;
998d3e94522SXu Kuohai }
999d3e94522SXu Kuohai 
1000d3e94522SXu Kuohai static void bpf_restore_subprog_starts(struct bpf_verifier_env *env, u32 *orig_starts)
1001d3e94522SXu Kuohai {
1002d3e94522SXu Kuohai 	for (int i = 0; i < env->subprog_cnt; i++)
1003d3e94522SXu Kuohai 		env->subprog_info[i].start = orig_starts[i];
1004d3e94522SXu Kuohai 	/* restore the start of fake 'exit' subprog as well */
1005d3e94522SXu Kuohai 	env->subprog_info[env->subprog_cnt].start = env->prog->len;
1006d3e94522SXu Kuohai }
1007d3e94522SXu Kuohai 
1008d9ef13f7SXu Kuohai struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
1009d3e94522SXu Kuohai {
1010d3e94522SXu Kuohai 	size_t size;
1011d3e94522SXu Kuohai 	void *new_aux;
1012d3e94522SXu Kuohai 
1013d3e94522SXu Kuohai 	size = array_size(sizeof(struct bpf_insn_aux_data), env->prog->len);
1014d3e94522SXu Kuohai 	new_aux = __vmalloc(size, GFP_KERNEL_ACCOUNT);
1015d3e94522SXu Kuohai 	if (new_aux)
1016d3e94522SXu Kuohai 		memcpy(new_aux, env->insn_aux_data, size);
1017d3e94522SXu Kuohai 	return new_aux;
1018d3e94522SXu Kuohai }
1019d3e94522SXu Kuohai 
1020d9ef13f7SXu Kuohai void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
1021d3e94522SXu Kuohai 			       struct bpf_insn_aux_data *orig_insn_aux)
1022d3e94522SXu Kuohai {
1023d3e94522SXu Kuohai 	/* the expanded elements are zero-filled, so no special handling is required */
1024d3e94522SXu Kuohai 	vfree(env->insn_aux_data);
1025d3e94522SXu Kuohai 	env->insn_aux_data = orig_insn_aux;
1026d3e94522SXu Kuohai }
1027d3e94522SXu Kuohai 
1028d3e94522SXu Kuohai static int jit_subprogs(struct bpf_verifier_env *env)
1029449f08faSAlexei Starovoitov {
1030449f08faSAlexei Starovoitov 	struct bpf_prog *prog = env->prog, **func, *tmp;
1031449f08faSAlexei Starovoitov 	int i, j, subprog_start, subprog_end = 0, len, subprog;
1032449f08faSAlexei Starovoitov 	struct bpf_map *map_ptr;
1033449f08faSAlexei Starovoitov 	struct bpf_insn *insn;
1034449f08faSAlexei Starovoitov 	void *old_bpf_func;
1035449f08faSAlexei Starovoitov 	int err, num_exentries;
1036449f08faSAlexei Starovoitov 
1037449f08faSAlexei Starovoitov 	for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
1038449f08faSAlexei Starovoitov 		if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn))
1039449f08faSAlexei Starovoitov 			continue;
1040449f08faSAlexei Starovoitov 
1041449f08faSAlexei Starovoitov 		/* Upon error here we cannot fall back to interpreter but
1042449f08faSAlexei Starovoitov 		 * need a hard reject of the program. Thus -EFAULT is
1043449f08faSAlexei Starovoitov 		 * propagated in any case.
1044449f08faSAlexei Starovoitov 		 */
1045449f08faSAlexei Starovoitov 		subprog = bpf_find_subprog(env, i + insn->imm + 1);
1046449f08faSAlexei Starovoitov 		if (verifier_bug_if(subprog < 0, env, "No program to jit at insn %d",
1047449f08faSAlexei Starovoitov 				    i + insn->imm + 1))
1048449f08faSAlexei Starovoitov 			return -EFAULT;
1049449f08faSAlexei Starovoitov 		/* temporarily remember subprog id inside insn instead of
1050449f08faSAlexei Starovoitov 		 * aux_data, since next loop will split up all insns into funcs
1051449f08faSAlexei Starovoitov 		 */
1052449f08faSAlexei Starovoitov 		insn->off = subprog;
1053449f08faSAlexei Starovoitov 		/* remember original imm in case JIT fails and fallback
1054449f08faSAlexei Starovoitov 		 * to interpreter will be needed
1055449f08faSAlexei Starovoitov 		 */
1056449f08faSAlexei Starovoitov 		env->insn_aux_data[i].call_imm = insn->imm;
1057449f08faSAlexei Starovoitov 		/* point imm to __bpf_call_base+1 from JITs point of view */
1058449f08faSAlexei Starovoitov 		insn->imm = 1;
1059449f08faSAlexei Starovoitov 		if (bpf_pseudo_func(insn)) {
1060449f08faSAlexei Starovoitov #if defined(MODULES_VADDR)
1061449f08faSAlexei Starovoitov 			u64 addr = MODULES_VADDR;
1062449f08faSAlexei Starovoitov #else
1063449f08faSAlexei Starovoitov 			u64 addr = VMALLOC_START;
1064449f08faSAlexei Starovoitov #endif
1065449f08faSAlexei Starovoitov 			/* jit (e.g. x86_64) may emit fewer instructions
1066449f08faSAlexei Starovoitov 			 * if it learns a u32 imm is the same as a u64 imm.
1067449f08faSAlexei Starovoitov 			 * Set close enough to possible prog address.
1068449f08faSAlexei Starovoitov 			 */
1069449f08faSAlexei Starovoitov 			insn[0].imm = (u32)addr;
1070449f08faSAlexei Starovoitov 			insn[1].imm = addr >> 32;
1071449f08faSAlexei Starovoitov 		}
1072449f08faSAlexei Starovoitov 	}
1073449f08faSAlexei Starovoitov 
1074449f08faSAlexei Starovoitov 	err = bpf_prog_alloc_jited_linfo(prog);
1075449f08faSAlexei Starovoitov 	if (err)
1076449f08faSAlexei Starovoitov 		goto out_undo_insn;
1077449f08faSAlexei Starovoitov 
1078449f08faSAlexei Starovoitov 	err = -ENOMEM;
1079449f08faSAlexei Starovoitov 	func = kzalloc_objs(prog, env->subprog_cnt);
1080449f08faSAlexei Starovoitov 	if (!func)
1081449f08faSAlexei Starovoitov 		goto out_undo_insn;
1082449f08faSAlexei Starovoitov 
1083449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
1084449f08faSAlexei Starovoitov 		subprog_start = subprog_end;
1085449f08faSAlexei Starovoitov 		subprog_end = env->subprog_info[i + 1].start;
1086449f08faSAlexei Starovoitov 
1087449f08faSAlexei Starovoitov 		len = subprog_end - subprog_start;
1088449f08faSAlexei Starovoitov 		/* bpf_prog_run() doesn't call subprogs directly,
1089449f08faSAlexei Starovoitov 		 * hence main prog stats include the runtime of subprogs.
1090449f08faSAlexei Starovoitov 		 * subprogs don't have IDs and not reachable via prog_get_next_id
1091449f08faSAlexei Starovoitov 		 * func[i]->stats will never be accessed and stays NULL
1092449f08faSAlexei Starovoitov 		 */
1093449f08faSAlexei Starovoitov 		func[i] = bpf_prog_alloc_no_stats(bpf_prog_size(len), GFP_USER);
1094449f08faSAlexei Starovoitov 		if (!func[i])
1095449f08faSAlexei Starovoitov 			goto out_free;
1096449f08faSAlexei Starovoitov 		memcpy(func[i]->insnsi, &prog->insnsi[subprog_start],
1097449f08faSAlexei Starovoitov 		       len * sizeof(struct bpf_insn));
1098449f08faSAlexei Starovoitov 		func[i]->type = prog->type;
1099449f08faSAlexei Starovoitov 		func[i]->len = len;
1100449f08faSAlexei Starovoitov 		if (bpf_prog_calc_tag(func[i]))
1101449f08faSAlexei Starovoitov 			goto out_free;
1102449f08faSAlexei Starovoitov 		func[i]->is_func = 1;
1103449f08faSAlexei Starovoitov 		func[i]->sleepable = prog->sleepable;
1104d3e94522SXu Kuohai 		func[i]->blinded = prog->blinded;
1105449f08faSAlexei Starovoitov 		func[i]->aux->func_idx = i;
1106449f08faSAlexei Starovoitov 		/* Below members will be freed only at prog->aux */
1107449f08faSAlexei Starovoitov 		func[i]->aux->btf = prog->aux->btf;
1108d3e94522SXu Kuohai 		func[i]->aux->subprog_start = subprog_start;
1109449f08faSAlexei Starovoitov 		func[i]->aux->func_info = prog->aux->func_info;
1110449f08faSAlexei Starovoitov 		func[i]->aux->func_info_cnt = prog->aux->func_info_cnt;
1111449f08faSAlexei Starovoitov 		func[i]->aux->poke_tab = prog->aux->poke_tab;
1112449f08faSAlexei Starovoitov 		func[i]->aux->size_poke_tab = prog->aux->size_poke_tab;
1113449f08faSAlexei Starovoitov 		func[i]->aux->main_prog_aux = prog->aux;
1114449f08faSAlexei Starovoitov 
1115449f08faSAlexei Starovoitov 		for (j = 0; j < prog->aux->size_poke_tab; j++) {
1116449f08faSAlexei Starovoitov 			struct bpf_jit_poke_descriptor *poke;
1117449f08faSAlexei Starovoitov 
1118449f08faSAlexei Starovoitov 			poke = &prog->aux->poke_tab[j];
1119449f08faSAlexei Starovoitov 			if (poke->insn_idx < subprog_end &&
1120449f08faSAlexei Starovoitov 			    poke->insn_idx >= subprog_start)
1121449f08faSAlexei Starovoitov 				poke->aux = func[i]->aux;
1122449f08faSAlexei Starovoitov 		}
1123449f08faSAlexei Starovoitov 
1124449f08faSAlexei Starovoitov 		func[i]->aux->name[0] = 'F';
1125449f08faSAlexei Starovoitov 		func[i]->aux->stack_depth = env->subprog_info[i].stack_depth;
1126449f08faSAlexei Starovoitov 		if (env->subprog_info[i].priv_stack_mode == PRIV_STACK_ADAPTIVE)
1127449f08faSAlexei Starovoitov 			func[i]->aux->jits_use_priv_stack = true;
1128449f08faSAlexei Starovoitov 
1129449f08faSAlexei Starovoitov 		func[i]->jit_requested = 1;
1130449f08faSAlexei Starovoitov 		func[i]->blinding_requested = prog->blinding_requested;
1131449f08faSAlexei Starovoitov 		func[i]->aux->kfunc_tab = prog->aux->kfunc_tab;
1132449f08faSAlexei Starovoitov 		func[i]->aux->kfunc_btf_tab = prog->aux->kfunc_btf_tab;
1133449f08faSAlexei Starovoitov 		func[i]->aux->linfo = prog->aux->linfo;
1134449f08faSAlexei Starovoitov 		func[i]->aux->nr_linfo = prog->aux->nr_linfo;
1135449f08faSAlexei Starovoitov 		func[i]->aux->jited_linfo = prog->aux->jited_linfo;
1136449f08faSAlexei Starovoitov 		func[i]->aux->linfo_idx = env->subprog_info[i].linfo_idx;
1137449f08faSAlexei Starovoitov 		func[i]->aux->arena = prog->aux->arena;
1138449f08faSAlexei Starovoitov 		func[i]->aux->used_maps = env->used_maps;
1139449f08faSAlexei Starovoitov 		func[i]->aux->used_map_cnt = env->used_map_cnt;
1140449f08faSAlexei Starovoitov 		num_exentries = 0;
1141449f08faSAlexei Starovoitov 		insn = func[i]->insnsi;
1142449f08faSAlexei Starovoitov 		for (j = 0; j < func[i]->len; j++, insn++) {
1143449f08faSAlexei Starovoitov 			if (BPF_CLASS(insn->code) == BPF_LDX &&
1144449f08faSAlexei Starovoitov 			    (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
1145449f08faSAlexei Starovoitov 			     BPF_MODE(insn->code) == BPF_PROBE_MEM32 ||
1146449f08faSAlexei Starovoitov 			     BPF_MODE(insn->code) == BPF_PROBE_MEM32SX ||
1147449f08faSAlexei Starovoitov 			     BPF_MODE(insn->code) == BPF_PROBE_MEMSX))
1148449f08faSAlexei Starovoitov 				num_exentries++;
1149449f08faSAlexei Starovoitov 			if ((BPF_CLASS(insn->code) == BPF_STX ||
1150449f08faSAlexei Starovoitov 			     BPF_CLASS(insn->code) == BPF_ST) &&
1151449f08faSAlexei Starovoitov 			     BPF_MODE(insn->code) == BPF_PROBE_MEM32)
1152449f08faSAlexei Starovoitov 				num_exentries++;
1153449f08faSAlexei Starovoitov 			if (BPF_CLASS(insn->code) == BPF_STX &&
1154449f08faSAlexei Starovoitov 			     BPF_MODE(insn->code) == BPF_PROBE_ATOMIC)
1155449f08faSAlexei Starovoitov 				num_exentries++;
1156449f08faSAlexei Starovoitov 		}
1157449f08faSAlexei Starovoitov 		func[i]->aux->num_exentries = num_exentries;
1158449f08faSAlexei Starovoitov 		func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable;
1159449f08faSAlexei Starovoitov 		func[i]->aux->exception_cb = env->subprog_info[i].is_exception_cb;
1160449f08faSAlexei Starovoitov 		func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data;
1161449f08faSAlexei Starovoitov 		func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
11620251e40cSEduard Zingerman 		func[i]->aux->token = prog->aux->token;
1163449f08faSAlexei Starovoitov 		if (!i)
1164449f08faSAlexei Starovoitov 			func[i]->aux->exception_boundary = env->seen_exception;
1165d9ef13f7SXu Kuohai 		func[i] = bpf_int_jit_compile(env, func[i]);
1166449f08faSAlexei Starovoitov 		if (!func[i]->jited) {
1167449f08faSAlexei Starovoitov 			err = -ENOTSUPP;
1168449f08faSAlexei Starovoitov 			goto out_free;
1169449f08faSAlexei Starovoitov 		}
1170449f08faSAlexei Starovoitov 		cond_resched();
1171449f08faSAlexei Starovoitov 	}
1172449f08faSAlexei Starovoitov 
1173449f08faSAlexei Starovoitov 	/* at this point all bpf functions were successfully JITed
1174449f08faSAlexei Starovoitov 	 * now populate all bpf_calls with correct addresses and
1175449f08faSAlexei Starovoitov 	 * run last pass of JIT
1176449f08faSAlexei Starovoitov 	 */
1177449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
1178449f08faSAlexei Starovoitov 		insn = func[i]->insnsi;
1179449f08faSAlexei Starovoitov 		for (j = 0; j < func[i]->len; j++, insn++) {
1180449f08faSAlexei Starovoitov 			if (bpf_pseudo_func(insn)) {
1181449f08faSAlexei Starovoitov 				subprog = insn->off;
1182449f08faSAlexei Starovoitov 				insn[0].imm = (u32)(long)func[subprog]->bpf_func;
1183449f08faSAlexei Starovoitov 				insn[1].imm = ((u64)(long)func[subprog]->bpf_func) >> 32;
1184449f08faSAlexei Starovoitov 				continue;
1185449f08faSAlexei Starovoitov 			}
1186449f08faSAlexei Starovoitov 			if (!bpf_pseudo_call(insn))
1187449f08faSAlexei Starovoitov 				continue;
1188449f08faSAlexei Starovoitov 			subprog = insn->off;
1189449f08faSAlexei Starovoitov 			insn->imm = BPF_CALL_IMM(func[subprog]->bpf_func);
1190449f08faSAlexei Starovoitov 		}
1191449f08faSAlexei Starovoitov 
1192449f08faSAlexei Starovoitov 		/* we use the aux data to keep a list of the start addresses
1193449f08faSAlexei Starovoitov 		 * of the JITed images for each function in the program
1194449f08faSAlexei Starovoitov 		 *
1195449f08faSAlexei Starovoitov 		 * for some architectures, such as powerpc64, the imm field
1196449f08faSAlexei Starovoitov 		 * might not be large enough to hold the offset of the start
1197449f08faSAlexei Starovoitov 		 * address of the callee's JITed image from __bpf_call_base
1198449f08faSAlexei Starovoitov 		 *
1199449f08faSAlexei Starovoitov 		 * in such cases, we can lookup the start address of a callee
1200449f08faSAlexei Starovoitov 		 * by using its subprog id, available from the off field of
1201449f08faSAlexei Starovoitov 		 * the call instruction, as an index for this list
1202449f08faSAlexei Starovoitov 		 */
1203449f08faSAlexei Starovoitov 		func[i]->aux->func = func;
1204449f08faSAlexei Starovoitov 		func[i]->aux->func_cnt = env->subprog_cnt - env->hidden_subprog_cnt;
1205449f08faSAlexei Starovoitov 		func[i]->aux->real_func_cnt = env->subprog_cnt;
1206449f08faSAlexei Starovoitov 	}
1207449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
1208449f08faSAlexei Starovoitov 		old_bpf_func = func[i]->bpf_func;
1209d9ef13f7SXu Kuohai 		tmp = bpf_int_jit_compile(env, func[i]);
1210449f08faSAlexei Starovoitov 		if (tmp != func[i] || func[i]->bpf_func != old_bpf_func) {
1211449f08faSAlexei Starovoitov 			verbose(env, "JIT doesn't support bpf-to-bpf calls\n");
1212449f08faSAlexei Starovoitov 			err = -ENOTSUPP;
1213449f08faSAlexei Starovoitov 			goto out_free;
1214449f08faSAlexei Starovoitov 		}
1215449f08faSAlexei Starovoitov 		cond_resched();
1216449f08faSAlexei Starovoitov 	}
1217449f08faSAlexei Starovoitov 
1218449f08faSAlexei Starovoitov 	/*
1219449f08faSAlexei Starovoitov 	 * Cleanup func[i]->aux fields which aren't required
1220449f08faSAlexei Starovoitov 	 * or can become invalid in future
1221449f08faSAlexei Starovoitov 	 */
1222449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
1223449f08faSAlexei Starovoitov 		func[i]->aux->used_maps = NULL;
1224449f08faSAlexei Starovoitov 		func[i]->aux->used_map_cnt = 0;
1225449f08faSAlexei Starovoitov 	}
1226449f08faSAlexei Starovoitov 
1227449f08faSAlexei Starovoitov 	/* finally lock prog and jit images for all functions and
1228449f08faSAlexei Starovoitov 	 * populate kallsysm. Begin at the first subprogram, since
1229449f08faSAlexei Starovoitov 	 * bpf_prog_load will add the kallsyms for the main program.
1230449f08faSAlexei Starovoitov 	 */
1231449f08faSAlexei Starovoitov 	for (i = 1; i < env->subprog_cnt; i++) {
1232449f08faSAlexei Starovoitov 		err = bpf_prog_lock_ro(func[i]);
1233449f08faSAlexei Starovoitov 		if (err)
1234449f08faSAlexei Starovoitov 			goto out_free;
1235449f08faSAlexei Starovoitov 	}
1236449f08faSAlexei Starovoitov 
1237449f08faSAlexei Starovoitov 	for (i = 1; i < env->subprog_cnt; i++)
1238449f08faSAlexei Starovoitov 		bpf_prog_kallsyms_add(func[i]);
1239449f08faSAlexei Starovoitov 
1240449f08faSAlexei Starovoitov 	/* Last step: make now unused interpreter insns from main
1241449f08faSAlexei Starovoitov 	 * prog consistent for later dump requests, so they can
1242449f08faSAlexei Starovoitov 	 * later look the same as if they were interpreted only.
1243449f08faSAlexei Starovoitov 	 */
1244449f08faSAlexei Starovoitov 	for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
1245449f08faSAlexei Starovoitov 		if (bpf_pseudo_func(insn)) {
1246449f08faSAlexei Starovoitov 			insn[0].imm = env->insn_aux_data[i].call_imm;
1247449f08faSAlexei Starovoitov 			insn[1].imm = insn->off;
1248449f08faSAlexei Starovoitov 			insn->off = 0;
1249449f08faSAlexei Starovoitov 			continue;
1250449f08faSAlexei Starovoitov 		}
1251449f08faSAlexei Starovoitov 		if (!bpf_pseudo_call(insn))
1252449f08faSAlexei Starovoitov 			continue;
1253449f08faSAlexei Starovoitov 		insn->off = env->insn_aux_data[i].call_imm;
1254449f08faSAlexei Starovoitov 		subprog = bpf_find_subprog(env, i + insn->off + 1);
1255449f08faSAlexei Starovoitov 		insn->imm = subprog;
1256449f08faSAlexei Starovoitov 	}
1257449f08faSAlexei Starovoitov 
1258449f08faSAlexei Starovoitov 	prog->jited = 1;
1259449f08faSAlexei Starovoitov 	prog->bpf_func = func[0]->bpf_func;
1260449f08faSAlexei Starovoitov 	prog->jited_len = func[0]->jited_len;
1261449f08faSAlexei Starovoitov 	prog->aux->extable = func[0]->aux->extable;
1262449f08faSAlexei Starovoitov 	prog->aux->num_exentries = func[0]->aux->num_exentries;
1263449f08faSAlexei Starovoitov 	prog->aux->func = func;
1264449f08faSAlexei Starovoitov 	prog->aux->func_cnt = env->subprog_cnt - env->hidden_subprog_cnt;
1265449f08faSAlexei Starovoitov 	prog->aux->real_func_cnt = env->subprog_cnt;
1266449f08faSAlexei Starovoitov 	prog->aux->bpf_exception_cb = (void *)func[env->exception_callback_subprog]->bpf_func;
1267449f08faSAlexei Starovoitov 	prog->aux->exception_boundary = func[0]->aux->exception_boundary;
1268449f08faSAlexei Starovoitov 	bpf_prog_jit_attempt_done(prog);
1269449f08faSAlexei Starovoitov 	return 0;
1270449f08faSAlexei Starovoitov out_free:
1271449f08faSAlexei Starovoitov 	/* We failed JIT'ing, so at this point we need to unregister poke
1272449f08faSAlexei Starovoitov 	 * descriptors from subprogs, so that kernel is not attempting to
1273449f08faSAlexei Starovoitov 	 * patch it anymore as we're freeing the subprog JIT memory.
1274449f08faSAlexei Starovoitov 	 */
1275449f08faSAlexei Starovoitov 	for (i = 0; i < prog->aux->size_poke_tab; i++) {
1276449f08faSAlexei Starovoitov 		map_ptr = prog->aux->poke_tab[i].tail_call.map;
1277449f08faSAlexei Starovoitov 		map_ptr->ops->map_poke_untrack(map_ptr, prog->aux);
1278449f08faSAlexei Starovoitov 	}
1279449f08faSAlexei Starovoitov 	/* At this point we're guaranteed that poke descriptors are not
1280449f08faSAlexei Starovoitov 	 * live anymore. We can just unlink its descriptor table as it's
1281449f08faSAlexei Starovoitov 	 * released with the main prog.
1282449f08faSAlexei Starovoitov 	 */
1283449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
1284449f08faSAlexei Starovoitov 		if (!func[i])
1285449f08faSAlexei Starovoitov 			continue;
1286449f08faSAlexei Starovoitov 		func[i]->aux->poke_tab = NULL;
1287449f08faSAlexei Starovoitov 		bpf_jit_free(func[i]);
1288449f08faSAlexei Starovoitov 	}
1289449f08faSAlexei Starovoitov 	kfree(func);
1290449f08faSAlexei Starovoitov out_undo_insn:
1291d3e94522SXu Kuohai 	bpf_prog_jit_attempt_done(prog);
1292d3e94522SXu Kuohai 	return err;
1293d3e94522SXu Kuohai }
1294d3e94522SXu Kuohai 
1295d3e94522SXu Kuohai int bpf_jit_subprogs(struct bpf_verifier_env *env)
1296d3e94522SXu Kuohai {
1297d3e94522SXu Kuohai 	int err, i;
1298d3e94522SXu Kuohai 	bool blinded = false;
1299d3e94522SXu Kuohai 	struct bpf_insn *insn;
1300d3e94522SXu Kuohai 	struct bpf_prog *prog, *orig_prog;
1301d3e94522SXu Kuohai 	struct bpf_insn_aux_data *orig_insn_aux;
1302d3e94522SXu Kuohai 	u32 *orig_subprog_starts;
1303d3e94522SXu Kuohai 
1304d3e94522SXu Kuohai 	if (env->subprog_cnt <= 1)
1305d3e94522SXu Kuohai 		return 0;
1306d3e94522SXu Kuohai 
1307d3e94522SXu Kuohai 	prog = orig_prog = env->prog;
1308d3e94522SXu Kuohai 	if (bpf_prog_need_blind(prog)) {
1309d3e94522SXu Kuohai 		orig_insn_aux = bpf_dup_insn_aux_data(env);
1310d3e94522SXu Kuohai 		if (!orig_insn_aux) {
1311d3e94522SXu Kuohai 			err = -ENOMEM;
1312d3e94522SXu Kuohai 			goto out_cleanup;
1313d3e94522SXu Kuohai 		}
1314d3e94522SXu Kuohai 		orig_subprog_starts = bpf_dup_subprog_starts(env);
1315d3e94522SXu Kuohai 		if (!orig_subprog_starts) {
1316d3e94522SXu Kuohai 			vfree(orig_insn_aux);
1317d3e94522SXu Kuohai 			err = -ENOMEM;
1318d3e94522SXu Kuohai 			goto out_cleanup;
1319d3e94522SXu Kuohai 		}
1320d3e94522SXu Kuohai 		prog = bpf_jit_blind_constants(env, prog);
1321d3e94522SXu Kuohai 		if (IS_ERR(prog)) {
1322d3e94522SXu Kuohai 			err = -ENOMEM;
1323d3e94522SXu Kuohai 			prog = orig_prog;
1324d3e94522SXu Kuohai 			goto out_restore;
1325d3e94522SXu Kuohai 		}
1326d3e94522SXu Kuohai 		blinded = true;
1327d3e94522SXu Kuohai 	}
1328d3e94522SXu Kuohai 
1329d3e94522SXu Kuohai 	err = jit_subprogs(env);
1330d3e94522SXu Kuohai 	if (err)
1331d3e94522SXu Kuohai 		goto out_jit_err;
1332d3e94522SXu Kuohai 
1333d3e94522SXu Kuohai 	if (blinded) {
1334d3e94522SXu Kuohai 		bpf_jit_prog_release_other(prog, orig_prog);
1335d3e94522SXu Kuohai 		kvfree(orig_subprog_starts);
1336d3e94522SXu Kuohai 		vfree(orig_insn_aux);
1337d3e94522SXu Kuohai 	}
1338d3e94522SXu Kuohai 
1339d3e94522SXu Kuohai 	return 0;
1340d3e94522SXu Kuohai 
1341d3e94522SXu Kuohai out_jit_err:
1342d3e94522SXu Kuohai 	if (blinded) {
1343d3e94522SXu Kuohai 		bpf_jit_prog_release_other(orig_prog, prog);
1344d3e94522SXu Kuohai 		/* roll back to the clean original prog */
1345d3e94522SXu Kuohai 		prog = env->prog = orig_prog;
1346d3e94522SXu Kuohai 		goto out_restore;
1347d3e94522SXu Kuohai 	} else {
1348d3e94522SXu Kuohai 		if (err != -EFAULT) {
1349d3e94522SXu Kuohai 			/*
1350d3e94522SXu Kuohai 			 * We will fall back to interpreter mode when err is not -EFAULT, before
1351d3e94522SXu Kuohai 			 * that, insn->off and insn->imm should be restored to their original
1352d3e94522SXu Kuohai 			 * values since they were modified by jit_subprogs.
1353d3e94522SXu Kuohai 			 */
1354449f08faSAlexei Starovoitov 			for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
1355449f08faSAlexei Starovoitov 				if (!bpf_pseudo_call(insn))
1356449f08faSAlexei Starovoitov 					continue;
1357449f08faSAlexei Starovoitov 				insn->off = 0;
1358449f08faSAlexei Starovoitov 				insn->imm = env->insn_aux_data[i].call_imm;
1359449f08faSAlexei Starovoitov 			}
1360d3e94522SXu Kuohai 		}
1361d3e94522SXu Kuohai 		goto out_cleanup;
1362d3e94522SXu Kuohai 	}
1363d3e94522SXu Kuohai 
1364d3e94522SXu Kuohai out_restore:
1365d3e94522SXu Kuohai 	bpf_restore_subprog_starts(env, orig_subprog_starts);
1366d3e94522SXu Kuohai 	bpf_restore_insn_aux_data(env, orig_insn_aux);
1367d3e94522SXu Kuohai 	kvfree(orig_subprog_starts);
1368d3e94522SXu Kuohai out_cleanup:
1369d3e94522SXu Kuohai 	/* cleanup main prog to be interpreted */
1370d3e94522SXu Kuohai 	prog->jit_requested = 0;
1371d3e94522SXu Kuohai 	prog->blinding_requested = 0;
1372449f08faSAlexei Starovoitov 	return err;
1373449f08faSAlexei Starovoitov }
1374449f08faSAlexei Starovoitov 
1375449f08faSAlexei Starovoitov int bpf_fixup_call_args(struct bpf_verifier_env *env)
1376449f08faSAlexei Starovoitov {
1377449f08faSAlexei Starovoitov #ifndef CONFIG_BPF_JIT_ALWAYS_ON
1378449f08faSAlexei Starovoitov 	struct bpf_prog *prog = env->prog;
1379449f08faSAlexei Starovoitov 	struct bpf_insn *insn = prog->insnsi;
1380449f08faSAlexei Starovoitov 	bool has_kfunc_call = bpf_prog_has_kfunc_call(prog);
1381449f08faSAlexei Starovoitov 	int i, depth;
1382449f08faSAlexei Starovoitov #endif
1383449f08faSAlexei Starovoitov 	int err = 0;
1384449f08faSAlexei Starovoitov 
1385449f08faSAlexei Starovoitov 	if (env->prog->jit_requested &&
1386449f08faSAlexei Starovoitov 	    !bpf_prog_is_offloaded(env->prog->aux)) {
1387449f08faSAlexei Starovoitov 		err = bpf_jit_subprogs(env);
1388449f08faSAlexei Starovoitov 		if (err == 0)
1389449f08faSAlexei Starovoitov 			return 0;
1390449f08faSAlexei Starovoitov 		if (err == -EFAULT)
1391449f08faSAlexei Starovoitov 			return err;
1392449f08faSAlexei Starovoitov 	}
1393449f08faSAlexei Starovoitov #ifndef CONFIG_BPF_JIT_ALWAYS_ON
1394449f08faSAlexei Starovoitov 	if (has_kfunc_call) {
1395449f08faSAlexei Starovoitov 		verbose(env, "calling kernel functions are not allowed in non-JITed programs\n");
1396449f08faSAlexei Starovoitov 		return -EINVAL;
1397449f08faSAlexei Starovoitov 	}
1398449f08faSAlexei Starovoitov 	if (env->subprog_cnt > 1 && env->prog->aux->tail_call_reachable) {
1399449f08faSAlexei Starovoitov 		/* When JIT fails the progs with bpf2bpf calls and tail_calls
1400449f08faSAlexei Starovoitov 		 * have to be rejected, since interpreter doesn't support them yet.
1401449f08faSAlexei Starovoitov 		 */
1402449f08faSAlexei Starovoitov 		verbose(env, "tail_calls are not allowed in non-JITed programs with bpf-to-bpf calls\n");
1403449f08faSAlexei Starovoitov 		return -EINVAL;
1404449f08faSAlexei Starovoitov 	}
1405449f08faSAlexei Starovoitov 	for (i = 0; i < prog->len; i++, insn++) {
1406449f08faSAlexei Starovoitov 		if (bpf_pseudo_func(insn)) {
1407449f08faSAlexei Starovoitov 			/* When JIT fails the progs with callback calls
1408449f08faSAlexei Starovoitov 			 * have to be rejected, since interpreter doesn't support them yet.
1409449f08faSAlexei Starovoitov 			 */
1410449f08faSAlexei Starovoitov 			verbose(env, "callbacks are not allowed in non-JITed programs\n");
1411449f08faSAlexei Starovoitov 			return -EINVAL;
1412449f08faSAlexei Starovoitov 		}
1413449f08faSAlexei Starovoitov 
1414449f08faSAlexei Starovoitov 		if (!bpf_pseudo_call(insn))
1415449f08faSAlexei Starovoitov 			continue;
1416449f08faSAlexei Starovoitov 		depth = get_callee_stack_depth(env, insn, i);
1417449f08faSAlexei Starovoitov 		if (depth < 0)
1418449f08faSAlexei Starovoitov 			return depth;
1419449f08faSAlexei Starovoitov 		bpf_patch_call_args(insn, depth);
1420449f08faSAlexei Starovoitov 	}
1421449f08faSAlexei Starovoitov 	err = 0;
1422449f08faSAlexei Starovoitov #endif
1423449f08faSAlexei Starovoitov 	return err;
1424449f08faSAlexei Starovoitov }
1425449f08faSAlexei Starovoitov 
1426449f08faSAlexei Starovoitov 
1427449f08faSAlexei Starovoitov /* The function requires that first instruction in 'patch' is insnsi[prog->len - 1] */
1428449f08faSAlexei Starovoitov static int add_hidden_subprog(struct bpf_verifier_env *env, struct bpf_insn *patch, int len)
1429449f08faSAlexei Starovoitov {
1430449f08faSAlexei Starovoitov 	struct bpf_subprog_info *info = env->subprog_info;
1431449f08faSAlexei Starovoitov 	int cnt = env->subprog_cnt;
1432449f08faSAlexei Starovoitov 	struct bpf_prog *prog;
1433449f08faSAlexei Starovoitov 
1434449f08faSAlexei Starovoitov 	/* We only reserve one slot for hidden subprogs in subprog_info. */
1435449f08faSAlexei Starovoitov 	if (env->hidden_subprog_cnt) {
1436449f08faSAlexei Starovoitov 		verifier_bug(env, "only one hidden subprog supported");
1437449f08faSAlexei Starovoitov 		return -EFAULT;
1438449f08faSAlexei Starovoitov 	}
1439449f08faSAlexei Starovoitov 	/* We're not patching any existing instruction, just appending the new
1440449f08faSAlexei Starovoitov 	 * ones for the hidden subprog. Hence all of the adjustment operations
1441449f08faSAlexei Starovoitov 	 * in bpf_patch_insn_data are no-ops.
1442449f08faSAlexei Starovoitov 	 */
1443449f08faSAlexei Starovoitov 	prog = bpf_patch_insn_data(env, env->prog->len - 1, patch, len);
1444449f08faSAlexei Starovoitov 	if (!prog)
1445449f08faSAlexei Starovoitov 		return -ENOMEM;
1446449f08faSAlexei Starovoitov 	env->prog = prog;
1447449f08faSAlexei Starovoitov 	info[cnt + 1].start = info[cnt].start;
1448449f08faSAlexei Starovoitov 	info[cnt].start = prog->len - len + 1;
1449449f08faSAlexei Starovoitov 	env->subprog_cnt++;
1450449f08faSAlexei Starovoitov 	env->hidden_subprog_cnt++;
1451449f08faSAlexei Starovoitov 	return 0;
1452449f08faSAlexei Starovoitov }
1453449f08faSAlexei Starovoitov 
1454449f08faSAlexei Starovoitov /* Do various post-verification rewrites in a single program pass.
1455449f08faSAlexei Starovoitov  * These rewrites simplify JIT and interpreter implementations.
1456449f08faSAlexei Starovoitov  */
1457449f08faSAlexei Starovoitov int bpf_do_misc_fixups(struct bpf_verifier_env *env)
1458449f08faSAlexei Starovoitov {
1459449f08faSAlexei Starovoitov 	struct bpf_prog *prog = env->prog;
1460449f08faSAlexei Starovoitov 	enum bpf_attach_type eatype = prog->expected_attach_type;
1461449f08faSAlexei Starovoitov 	enum bpf_prog_type prog_type = resolve_prog_type(prog);
1462449f08faSAlexei Starovoitov 	struct bpf_insn *insn = prog->insnsi;
1463449f08faSAlexei Starovoitov 	const struct bpf_func_proto *fn;
1464449f08faSAlexei Starovoitov 	const int insn_cnt = prog->len;
1465449f08faSAlexei Starovoitov 	const struct bpf_map_ops *ops;
1466449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux;
1467449f08faSAlexei Starovoitov 	struct bpf_insn *insn_buf = env->insn_buf;
1468449f08faSAlexei Starovoitov 	struct bpf_prog *new_prog;
1469449f08faSAlexei Starovoitov 	struct bpf_map *map_ptr;
1470449f08faSAlexei Starovoitov 	int i, ret, cnt, delta = 0, cur_subprog = 0;
1471449f08faSAlexei Starovoitov 	struct bpf_subprog_info *subprogs = env->subprog_info;
1472449f08faSAlexei Starovoitov 	u16 stack_depth = subprogs[cur_subprog].stack_depth;
1473449f08faSAlexei Starovoitov 	u16 stack_depth_extra = 0;
1474449f08faSAlexei Starovoitov 
1475449f08faSAlexei Starovoitov 	if (env->seen_exception && !env->exception_callback_subprog) {
1476449f08faSAlexei Starovoitov 		struct bpf_insn *patch = insn_buf;
1477449f08faSAlexei Starovoitov 
1478449f08faSAlexei Starovoitov 		*patch++ = env->prog->insnsi[insn_cnt - 1];
1479449f08faSAlexei Starovoitov 		*patch++ = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
1480449f08faSAlexei Starovoitov 		*patch++ = BPF_EXIT_INSN();
1481449f08faSAlexei Starovoitov 		ret = add_hidden_subprog(env, insn_buf, patch - insn_buf);
1482449f08faSAlexei Starovoitov 		if (ret < 0)
1483449f08faSAlexei Starovoitov 			return ret;
1484449f08faSAlexei Starovoitov 		prog = env->prog;
1485449f08faSAlexei Starovoitov 		insn = prog->insnsi;
1486449f08faSAlexei Starovoitov 
1487449f08faSAlexei Starovoitov 		env->exception_callback_subprog = env->subprog_cnt - 1;
1488449f08faSAlexei Starovoitov 		/* Don't update insn_cnt, as add_hidden_subprog always appends insns */
1489449f08faSAlexei Starovoitov 		bpf_mark_subprog_exc_cb(env, env->exception_callback_subprog);
1490449f08faSAlexei Starovoitov 	}
1491449f08faSAlexei Starovoitov 
1492449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt;) {
1493449f08faSAlexei Starovoitov 		if (insn->code == (BPF_ALU64 | BPF_MOV | BPF_X) && insn->imm) {
1494449f08faSAlexei Starovoitov 			if ((insn->off == BPF_ADDR_SPACE_CAST && insn->imm == 1) ||
1495449f08faSAlexei Starovoitov 			    (((struct bpf_map *)env->prog->aux->arena)->map_flags & BPF_F_NO_USER_CONV)) {
1496449f08faSAlexei Starovoitov 				/* convert to 32-bit mov that clears upper 32-bit */
1497449f08faSAlexei Starovoitov 				insn->code = BPF_ALU | BPF_MOV | BPF_X;
1498449f08faSAlexei Starovoitov 				/* clear off and imm, so it's a normal 'wX = wY' from JIT pov */
1499449f08faSAlexei Starovoitov 				insn->off = 0;
1500449f08faSAlexei Starovoitov 				insn->imm = 0;
1501449f08faSAlexei Starovoitov 			} /* cast from as(0) to as(1) should be handled by JIT */
1502449f08faSAlexei Starovoitov 			goto next_insn;
1503449f08faSAlexei Starovoitov 		}
1504449f08faSAlexei Starovoitov 
1505449f08faSAlexei Starovoitov 		if (env->insn_aux_data[i + delta].needs_zext)
1506449f08faSAlexei Starovoitov 			/* Convert BPF_CLASS(insn->code) == BPF_ALU64 to 32-bit ALU */
1507449f08faSAlexei Starovoitov 			insn->code = BPF_ALU | BPF_OP(insn->code) | BPF_SRC(insn->code);
1508449f08faSAlexei Starovoitov 
1509449f08faSAlexei Starovoitov 		/* Make sdiv/smod divide-by-minus-one exceptions impossible. */
1510449f08faSAlexei Starovoitov 		if ((insn->code == (BPF_ALU64 | BPF_MOD | BPF_K) ||
1511449f08faSAlexei Starovoitov 		     insn->code == (BPF_ALU64 | BPF_DIV | BPF_K) ||
1512449f08faSAlexei Starovoitov 		     insn->code == (BPF_ALU | BPF_MOD | BPF_K) ||
1513449f08faSAlexei Starovoitov 		     insn->code == (BPF_ALU | BPF_DIV | BPF_K)) &&
1514449f08faSAlexei Starovoitov 		    insn->off == 1 && insn->imm == -1) {
1515449f08faSAlexei Starovoitov 			bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
1516449f08faSAlexei Starovoitov 			bool isdiv = BPF_OP(insn->code) == BPF_DIV;
1517449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
1518449f08faSAlexei Starovoitov 
1519449f08faSAlexei Starovoitov 			if (isdiv)
1520449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
1521449f08faSAlexei Starovoitov 							BPF_NEG | BPF_K, insn->dst_reg,
1522449f08faSAlexei Starovoitov 							0, 0, 0);
1523449f08faSAlexei Starovoitov 			else
1524449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV32_IMM(insn->dst_reg, 0);
1525449f08faSAlexei Starovoitov 
1526449f08faSAlexei Starovoitov 			cnt = patch - insn_buf;
1527449f08faSAlexei Starovoitov 
1528449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1529449f08faSAlexei Starovoitov 			if (!new_prog)
1530449f08faSAlexei Starovoitov 				return -ENOMEM;
1531449f08faSAlexei Starovoitov 
1532449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1533449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1534449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1535449f08faSAlexei Starovoitov 			goto next_insn;
1536449f08faSAlexei Starovoitov 		}
1537449f08faSAlexei Starovoitov 
1538449f08faSAlexei Starovoitov 		/* Make divide-by-zero and divide-by-minus-one exceptions impossible. */
1539449f08faSAlexei Starovoitov 		if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) ||
1540449f08faSAlexei Starovoitov 		    insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) ||
1541449f08faSAlexei Starovoitov 		    insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
1542449f08faSAlexei Starovoitov 		    insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
1543449f08faSAlexei Starovoitov 			bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
1544449f08faSAlexei Starovoitov 			bool isdiv = BPF_OP(insn->code) == BPF_DIV;
1545449f08faSAlexei Starovoitov 			bool is_sdiv = isdiv && insn->off == 1;
1546449f08faSAlexei Starovoitov 			bool is_smod = !isdiv && insn->off == 1;
1547449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
1548449f08faSAlexei Starovoitov 
1549449f08faSAlexei Starovoitov 			if (is_sdiv) {
1550449f08faSAlexei Starovoitov 				/* [R,W]x sdiv 0 -> 0
1551449f08faSAlexei Starovoitov 				 * LLONG_MIN sdiv -1 -> LLONG_MIN
1552449f08faSAlexei Starovoitov 				 * INT_MIN sdiv -1 -> INT_MIN
1553449f08faSAlexei Starovoitov 				 */
1554449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV64_REG(BPF_REG_AX, insn->src_reg);
1555449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
1556449f08faSAlexei Starovoitov 							BPF_ADD | BPF_K, BPF_REG_AX,
1557449f08faSAlexei Starovoitov 							0, 0, 1);
1558449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1559449f08faSAlexei Starovoitov 							BPF_JGT | BPF_K, BPF_REG_AX,
1560449f08faSAlexei Starovoitov 							0, 4, 1);
1561449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1562449f08faSAlexei Starovoitov 							BPF_JEQ | BPF_K, BPF_REG_AX,
1563449f08faSAlexei Starovoitov 							0, 1, 0);
1564449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
1565449f08faSAlexei Starovoitov 							BPF_MOV | BPF_K, insn->dst_reg,
1566449f08faSAlexei Starovoitov 							0, 0, 0);
1567449f08faSAlexei Starovoitov 				/* BPF_NEG(LLONG_MIN) == -LLONG_MIN == LLONG_MIN */
1568449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
1569449f08faSAlexei Starovoitov 							BPF_NEG | BPF_K, insn->dst_reg,
1570449f08faSAlexei Starovoitov 							0, 0, 0);
1571449f08faSAlexei Starovoitov 				*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1572449f08faSAlexei Starovoitov 				*patch++ = *insn;
1573449f08faSAlexei Starovoitov 				cnt = patch - insn_buf;
1574449f08faSAlexei Starovoitov 			} else if (is_smod) {
1575449f08faSAlexei Starovoitov 				/* [R,W]x mod 0 -> [R,W]x */
1576449f08faSAlexei Starovoitov 				/* [R,W]x mod -1 -> 0 */
1577449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV64_REG(BPF_REG_AX, insn->src_reg);
1578449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_ALU64 : BPF_ALU) |
1579449f08faSAlexei Starovoitov 							BPF_ADD | BPF_K, BPF_REG_AX,
1580449f08faSAlexei Starovoitov 							0, 0, 1);
1581449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1582449f08faSAlexei Starovoitov 							BPF_JGT | BPF_K, BPF_REG_AX,
1583449f08faSAlexei Starovoitov 							0, 3, 1);
1584449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1585449f08faSAlexei Starovoitov 							BPF_JEQ | BPF_K, BPF_REG_AX,
1586449f08faSAlexei Starovoitov 							0, 3 + (is64 ? 0 : 1), 1);
1587449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV32_IMM(insn->dst_reg, 0);
1588449f08faSAlexei Starovoitov 				*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1589449f08faSAlexei Starovoitov 				*patch++ = *insn;
1590449f08faSAlexei Starovoitov 
1591449f08faSAlexei Starovoitov 				if (!is64) {
1592449f08faSAlexei Starovoitov 					*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1593449f08faSAlexei Starovoitov 					*patch++ = BPF_MOV32_REG(insn->dst_reg, insn->dst_reg);
1594449f08faSAlexei Starovoitov 				}
1595449f08faSAlexei Starovoitov 				cnt = patch - insn_buf;
1596449f08faSAlexei Starovoitov 			} else if (isdiv) {
1597449f08faSAlexei Starovoitov 				/* [R,W]x div 0 -> 0 */
1598449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1599449f08faSAlexei Starovoitov 							BPF_JNE | BPF_K, insn->src_reg,
1600449f08faSAlexei Starovoitov 							0, 2, 0);
1601449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU32_REG(BPF_XOR, insn->dst_reg, insn->dst_reg);
1602449f08faSAlexei Starovoitov 				*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1603449f08faSAlexei Starovoitov 				*patch++ = *insn;
1604449f08faSAlexei Starovoitov 				cnt = patch - insn_buf;
1605449f08faSAlexei Starovoitov 			} else {
1606449f08faSAlexei Starovoitov 				/* [R,W]x mod 0 -> [R,W]x */
1607449f08faSAlexei Starovoitov 				*patch++ = BPF_RAW_INSN((is64 ? BPF_JMP : BPF_JMP32) |
1608449f08faSAlexei Starovoitov 							BPF_JEQ | BPF_K, insn->src_reg,
1609449f08faSAlexei Starovoitov 							0, 1 + (is64 ? 0 : 1), 0);
1610449f08faSAlexei Starovoitov 				*patch++ = *insn;
1611449f08faSAlexei Starovoitov 
1612449f08faSAlexei Starovoitov 				if (!is64) {
1613449f08faSAlexei Starovoitov 					*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1614449f08faSAlexei Starovoitov 					*patch++ = BPF_MOV32_REG(insn->dst_reg, insn->dst_reg);
1615449f08faSAlexei Starovoitov 				}
1616449f08faSAlexei Starovoitov 				cnt = patch - insn_buf;
1617449f08faSAlexei Starovoitov 			}
1618449f08faSAlexei Starovoitov 
1619449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1620449f08faSAlexei Starovoitov 			if (!new_prog)
1621449f08faSAlexei Starovoitov 				return -ENOMEM;
1622449f08faSAlexei Starovoitov 
1623449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1624449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1625449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1626449f08faSAlexei Starovoitov 			goto next_insn;
1627449f08faSAlexei Starovoitov 		}
1628449f08faSAlexei Starovoitov 
1629449f08faSAlexei Starovoitov 		/* Make it impossible to de-reference a userspace address */
1630449f08faSAlexei Starovoitov 		if (BPF_CLASS(insn->code) == BPF_LDX &&
1631449f08faSAlexei Starovoitov 		    (BPF_MODE(insn->code) == BPF_PROBE_MEM ||
1632449f08faSAlexei Starovoitov 		     BPF_MODE(insn->code) == BPF_PROBE_MEMSX)) {
1633449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
1634449f08faSAlexei Starovoitov 			u64 uaddress_limit = bpf_arch_uaddress_limit();
1635449f08faSAlexei Starovoitov 
1636449f08faSAlexei Starovoitov 			if (!uaddress_limit)
1637449f08faSAlexei Starovoitov 				goto next_insn;
1638449f08faSAlexei Starovoitov 
1639449f08faSAlexei Starovoitov 			*patch++ = BPF_MOV64_REG(BPF_REG_AX, insn->src_reg);
1640449f08faSAlexei Starovoitov 			if (insn->off)
1641449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_IMM(BPF_ADD, BPF_REG_AX, insn->off);
1642449f08faSAlexei Starovoitov 			*patch++ = BPF_ALU64_IMM(BPF_RSH, BPF_REG_AX, 32);
1643449f08faSAlexei Starovoitov 			*patch++ = BPF_JMP_IMM(BPF_JLE, BPF_REG_AX, uaddress_limit >> 32, 2);
1644449f08faSAlexei Starovoitov 			*patch++ = *insn;
1645449f08faSAlexei Starovoitov 			*patch++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
1646449f08faSAlexei Starovoitov 			*patch++ = BPF_MOV64_IMM(insn->dst_reg, 0);
1647449f08faSAlexei Starovoitov 
1648449f08faSAlexei Starovoitov 			cnt = patch - insn_buf;
1649449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1650449f08faSAlexei Starovoitov 			if (!new_prog)
1651449f08faSAlexei Starovoitov 				return -ENOMEM;
1652449f08faSAlexei Starovoitov 
1653449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1654449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1655449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1656449f08faSAlexei Starovoitov 			goto next_insn;
1657449f08faSAlexei Starovoitov 		}
1658449f08faSAlexei Starovoitov 
1659449f08faSAlexei Starovoitov 		/* Implement LD_ABS and LD_IND with a rewrite, if supported by the program type. */
1660449f08faSAlexei Starovoitov 		if (BPF_CLASS(insn->code) == BPF_LD &&
1661449f08faSAlexei Starovoitov 		    (BPF_MODE(insn->code) == BPF_ABS ||
1662449f08faSAlexei Starovoitov 		     BPF_MODE(insn->code) == BPF_IND)) {
1663449f08faSAlexei Starovoitov 			cnt = env->ops->gen_ld_abs(insn, insn_buf);
1664449f08faSAlexei Starovoitov 			if (cnt == 0 || cnt >= INSN_BUF_SIZE) {
1665449f08faSAlexei Starovoitov 				verifier_bug(env, "%d insns generated for ld_abs", cnt);
1666449f08faSAlexei Starovoitov 				return -EFAULT;
1667449f08faSAlexei Starovoitov 			}
1668449f08faSAlexei Starovoitov 
1669449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1670449f08faSAlexei Starovoitov 			if (!new_prog)
1671449f08faSAlexei Starovoitov 				return -ENOMEM;
1672449f08faSAlexei Starovoitov 
1673449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1674449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1675449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1676449f08faSAlexei Starovoitov 			goto next_insn;
1677449f08faSAlexei Starovoitov 		}
1678449f08faSAlexei Starovoitov 
1679449f08faSAlexei Starovoitov 		/* Rewrite pointer arithmetic to mitigate speculation attacks. */
1680449f08faSAlexei Starovoitov 		if (insn->code == (BPF_ALU64 | BPF_ADD | BPF_X) ||
1681449f08faSAlexei Starovoitov 		    insn->code == (BPF_ALU64 | BPF_SUB | BPF_X)) {
1682449f08faSAlexei Starovoitov 			const u8 code_add = BPF_ALU64 | BPF_ADD | BPF_X;
1683449f08faSAlexei Starovoitov 			const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X;
1684449f08faSAlexei Starovoitov 			struct bpf_insn *patch = insn_buf;
1685449f08faSAlexei Starovoitov 			bool issrc, isneg, isimm;
1686449f08faSAlexei Starovoitov 			u32 off_reg;
1687449f08faSAlexei Starovoitov 
1688449f08faSAlexei Starovoitov 			aux = &env->insn_aux_data[i + delta];
1689449f08faSAlexei Starovoitov 			if (!aux->alu_state ||
1690449f08faSAlexei Starovoitov 			    aux->alu_state == BPF_ALU_NON_POINTER)
1691449f08faSAlexei Starovoitov 				goto next_insn;
1692449f08faSAlexei Starovoitov 
1693449f08faSAlexei Starovoitov 			isneg = aux->alu_state & BPF_ALU_NEG_VALUE;
1694449f08faSAlexei Starovoitov 			issrc = (aux->alu_state & BPF_ALU_SANITIZE) ==
1695449f08faSAlexei Starovoitov 				BPF_ALU_SANITIZE_SRC;
1696449f08faSAlexei Starovoitov 			isimm = aux->alu_state & BPF_ALU_IMMEDIATE;
1697449f08faSAlexei Starovoitov 
1698449f08faSAlexei Starovoitov 			off_reg = issrc ? insn->src_reg : insn->dst_reg;
1699449f08faSAlexei Starovoitov 			if (isimm) {
1700449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit);
1701449f08faSAlexei Starovoitov 			} else {
1702449f08faSAlexei Starovoitov 				if (isneg)
1703449f08faSAlexei Starovoitov 					*patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
1704449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit);
1705449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
1706449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
1707449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
1708449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63);
1709449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg);
1710449f08faSAlexei Starovoitov 			}
1711449f08faSAlexei Starovoitov 			if (!issrc)
1712449f08faSAlexei Starovoitov 				*patch++ = BPF_MOV64_REG(insn->dst_reg, insn->src_reg);
1713449f08faSAlexei Starovoitov 			insn->src_reg = BPF_REG_AX;
1714449f08faSAlexei Starovoitov 			if (isneg)
1715449f08faSAlexei Starovoitov 				insn->code = insn->code == code_add ?
1716449f08faSAlexei Starovoitov 					     code_sub : code_add;
1717449f08faSAlexei Starovoitov 			*patch++ = *insn;
1718449f08faSAlexei Starovoitov 			if (issrc && isneg && !isimm)
1719449f08faSAlexei Starovoitov 				*patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
1720449f08faSAlexei Starovoitov 			cnt = patch - insn_buf;
1721449f08faSAlexei Starovoitov 
1722449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1723449f08faSAlexei Starovoitov 			if (!new_prog)
1724449f08faSAlexei Starovoitov 				return -ENOMEM;
1725449f08faSAlexei Starovoitov 
1726449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1727449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1728449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1729449f08faSAlexei Starovoitov 			goto next_insn;
1730449f08faSAlexei Starovoitov 		}
1731449f08faSAlexei Starovoitov 
1732449f08faSAlexei Starovoitov 		if (bpf_is_may_goto_insn(insn) && bpf_jit_supports_timed_may_goto()) {
1733449f08faSAlexei Starovoitov 			int stack_off_cnt = -stack_depth - 16;
1734449f08faSAlexei Starovoitov 
1735449f08faSAlexei Starovoitov 			/*
1736449f08faSAlexei Starovoitov 			 * Two 8 byte slots, depth-16 stores the count, and
1737449f08faSAlexei Starovoitov 			 * depth-8 stores the start timestamp of the loop.
1738449f08faSAlexei Starovoitov 			 *
1739449f08faSAlexei Starovoitov 			 * The starting value of count is BPF_MAX_TIMED_LOOPS
1740449f08faSAlexei Starovoitov 			 * (0xffff).  Every iteration loads it and subs it by 1,
1741449f08faSAlexei Starovoitov 			 * until the value becomes 0 in AX (thus, 1 in stack),
1742449f08faSAlexei Starovoitov 			 * after which we call arch_bpf_timed_may_goto, which
1743449f08faSAlexei Starovoitov 			 * either sets AX to 0xffff to keep looping, or to 0
1744449f08faSAlexei Starovoitov 			 * upon timeout. AX is then stored into the stack. In
1745449f08faSAlexei Starovoitov 			 * the next iteration, we either see 0 and break out, or
1746449f08faSAlexei Starovoitov 			 * continue iterating until the next time value is 0
1747449f08faSAlexei Starovoitov 			 * after subtraction, rinse and repeat.
1748449f08faSAlexei Starovoitov 			 */
1749449f08faSAlexei Starovoitov 			stack_depth_extra = 16;
1750449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off_cnt);
1751449f08faSAlexei Starovoitov 			if (insn->off >= 0)
1752449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 5);
1753449f08faSAlexei Starovoitov 			else
1754449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off - 1);
1755449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1);
1756449f08faSAlexei Starovoitov 			insn_buf[3] = BPF_JMP_IMM(BPF_JNE, BPF_REG_AX, 0, 2);
1757449f08faSAlexei Starovoitov 			/*
1758449f08faSAlexei Starovoitov 			 * AX is used as an argument to pass in stack_off_cnt
1759449f08faSAlexei Starovoitov 			 * (to add to r10/fp), and also as the return value of
1760449f08faSAlexei Starovoitov 			 * the call to arch_bpf_timed_may_goto.
1761449f08faSAlexei Starovoitov 			 */
1762449f08faSAlexei Starovoitov 			insn_buf[4] = BPF_MOV64_IMM(BPF_REG_AX, stack_off_cnt);
1763449f08faSAlexei Starovoitov 			insn_buf[5] = BPF_EMIT_CALL(arch_bpf_timed_may_goto);
1764449f08faSAlexei Starovoitov 			insn_buf[6] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off_cnt);
1765449f08faSAlexei Starovoitov 			cnt = 7;
1766449f08faSAlexei Starovoitov 
1767449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1768449f08faSAlexei Starovoitov 			if (!new_prog)
1769449f08faSAlexei Starovoitov 				return -ENOMEM;
1770449f08faSAlexei Starovoitov 
1771449f08faSAlexei Starovoitov 			delta += cnt - 1;
1772449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1773449f08faSAlexei Starovoitov 			insn = new_prog->insnsi + i + delta;
1774449f08faSAlexei Starovoitov 			goto next_insn;
1775449f08faSAlexei Starovoitov 		} else if (bpf_is_may_goto_insn(insn)) {
1776449f08faSAlexei Starovoitov 			int stack_off = -stack_depth - 8;
1777449f08faSAlexei Starovoitov 
1778449f08faSAlexei Starovoitov 			stack_depth_extra = 8;
1779449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_AX, BPF_REG_10, stack_off);
1780449f08faSAlexei Starovoitov 			if (insn->off >= 0)
1781449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off + 2);
1782449f08faSAlexei Starovoitov 			else
1783449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, insn->off - 1);
1784449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_ALU64_IMM(BPF_SUB, BPF_REG_AX, 1);
1785449f08faSAlexei Starovoitov 			insn_buf[3] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_AX, stack_off);
1786449f08faSAlexei Starovoitov 			cnt = 4;
1787449f08faSAlexei Starovoitov 
1788449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1789449f08faSAlexei Starovoitov 			if (!new_prog)
1790449f08faSAlexei Starovoitov 				return -ENOMEM;
1791449f08faSAlexei Starovoitov 
1792449f08faSAlexei Starovoitov 			delta += cnt - 1;
1793449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1794449f08faSAlexei Starovoitov 			insn = new_prog->insnsi + i + delta;
1795449f08faSAlexei Starovoitov 			goto next_insn;
1796449f08faSAlexei Starovoitov 		}
1797449f08faSAlexei Starovoitov 
1798449f08faSAlexei Starovoitov 		if (insn->code != (BPF_JMP | BPF_CALL))
1799449f08faSAlexei Starovoitov 			goto next_insn;
1800449f08faSAlexei Starovoitov 		if (insn->src_reg == BPF_PSEUDO_CALL)
1801449f08faSAlexei Starovoitov 			goto next_insn;
1802449f08faSAlexei Starovoitov 		if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
1803449f08faSAlexei Starovoitov 			ret = bpf_fixup_kfunc_call(env, insn, insn_buf, i + delta, &cnt);
1804449f08faSAlexei Starovoitov 			if (ret)
1805449f08faSAlexei Starovoitov 				return ret;
1806449f08faSAlexei Starovoitov 			if (cnt == 0)
1807449f08faSAlexei Starovoitov 				goto next_insn;
1808449f08faSAlexei Starovoitov 
1809449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1810449f08faSAlexei Starovoitov 			if (!new_prog)
1811449f08faSAlexei Starovoitov 				return -ENOMEM;
1812449f08faSAlexei Starovoitov 
1813449f08faSAlexei Starovoitov 			delta	 += cnt - 1;
1814449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1815449f08faSAlexei Starovoitov 			insn	  = new_prog->insnsi + i + delta;
1816449f08faSAlexei Starovoitov 			goto next_insn;
1817449f08faSAlexei Starovoitov 		}
1818449f08faSAlexei Starovoitov 
1819449f08faSAlexei Starovoitov 		/* Skip inlining the helper call if the JIT does it. */
1820449f08faSAlexei Starovoitov 		if (bpf_jit_inlines_helper_call(insn->imm))
1821449f08faSAlexei Starovoitov 			goto next_insn;
1822449f08faSAlexei Starovoitov 
1823449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_get_route_realm)
1824449f08faSAlexei Starovoitov 			prog->dst_needed = 1;
1825449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_get_prandom_u32)
1826449f08faSAlexei Starovoitov 			bpf_user_rnd_init_once();
1827449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_override_return)
1828449f08faSAlexei Starovoitov 			prog->kprobe_override = 1;
1829449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_tail_call) {
1830449f08faSAlexei Starovoitov 			/* If we tail call into other programs, we
1831449f08faSAlexei Starovoitov 			 * cannot make any assumptions since they can
1832449f08faSAlexei Starovoitov 			 * be replaced dynamically during runtime in
1833449f08faSAlexei Starovoitov 			 * the program array.
1834449f08faSAlexei Starovoitov 			 */
1835449f08faSAlexei Starovoitov 			prog->cb_access = 1;
1836449f08faSAlexei Starovoitov 			if (!bpf_allow_tail_call_in_subprogs(env))
1837449f08faSAlexei Starovoitov 				prog->aux->stack_depth = MAX_BPF_STACK;
1838449f08faSAlexei Starovoitov 			prog->aux->max_pkt_offset = MAX_PACKET_OFF;
1839449f08faSAlexei Starovoitov 
1840449f08faSAlexei Starovoitov 			/* mark bpf_tail_call as different opcode to avoid
1841449f08faSAlexei Starovoitov 			 * conditional branch in the interpreter for every normal
1842449f08faSAlexei Starovoitov 			 * call and to prevent accidental JITing by JIT compiler
1843449f08faSAlexei Starovoitov 			 * that doesn't support bpf_tail_call yet
1844449f08faSAlexei Starovoitov 			 */
1845449f08faSAlexei Starovoitov 			insn->imm = 0;
1846449f08faSAlexei Starovoitov 			insn->code = BPF_JMP | BPF_TAIL_CALL;
1847449f08faSAlexei Starovoitov 
1848449f08faSAlexei Starovoitov 			aux = &env->insn_aux_data[i + delta];
1849449f08faSAlexei Starovoitov 			if (env->bpf_capable && !prog->blinding_requested &&
1850449f08faSAlexei Starovoitov 			    prog->jit_requested &&
1851449f08faSAlexei Starovoitov 			    !bpf_map_key_poisoned(aux) &&
1852449f08faSAlexei Starovoitov 			    !bpf_map_ptr_poisoned(aux) &&
1853449f08faSAlexei Starovoitov 			    !bpf_map_ptr_unpriv(aux)) {
1854449f08faSAlexei Starovoitov 				struct bpf_jit_poke_descriptor desc = {
1855449f08faSAlexei Starovoitov 					.reason = BPF_POKE_REASON_TAIL_CALL,
1856449f08faSAlexei Starovoitov 					.tail_call.map = aux->map_ptr_state.map_ptr,
1857449f08faSAlexei Starovoitov 					.tail_call.key = bpf_map_key_immediate(aux),
1858449f08faSAlexei Starovoitov 					.insn_idx = i + delta,
1859449f08faSAlexei Starovoitov 				};
1860449f08faSAlexei Starovoitov 
1861449f08faSAlexei Starovoitov 				ret = bpf_jit_add_poke_descriptor(prog, &desc);
1862449f08faSAlexei Starovoitov 				if (ret < 0) {
1863449f08faSAlexei Starovoitov 					verbose(env, "adding tail call poke descriptor failed\n");
1864449f08faSAlexei Starovoitov 					return ret;
1865449f08faSAlexei Starovoitov 				}
1866449f08faSAlexei Starovoitov 
1867449f08faSAlexei Starovoitov 				insn->imm = ret + 1;
1868449f08faSAlexei Starovoitov 				goto next_insn;
1869449f08faSAlexei Starovoitov 			}
1870449f08faSAlexei Starovoitov 
1871449f08faSAlexei Starovoitov 			if (!bpf_map_ptr_unpriv(aux))
1872449f08faSAlexei Starovoitov 				goto next_insn;
1873449f08faSAlexei Starovoitov 
1874449f08faSAlexei Starovoitov 			/* instead of changing every JIT dealing with tail_call
1875449f08faSAlexei Starovoitov 			 * emit two extra insns:
1876449f08faSAlexei Starovoitov 			 * if (index >= max_entries) goto out;
1877449f08faSAlexei Starovoitov 			 * index &= array->index_mask;
1878449f08faSAlexei Starovoitov 			 * to avoid out-of-bounds cpu speculation
1879449f08faSAlexei Starovoitov 			 */
1880449f08faSAlexei Starovoitov 			if (bpf_map_ptr_poisoned(aux)) {
1881449f08faSAlexei Starovoitov 				verbose(env, "tail_call abusing map_ptr\n");
1882449f08faSAlexei Starovoitov 				return -EINVAL;
1883449f08faSAlexei Starovoitov 			}
1884449f08faSAlexei Starovoitov 
1885449f08faSAlexei Starovoitov 			map_ptr = aux->map_ptr_state.map_ptr;
1886449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3,
1887449f08faSAlexei Starovoitov 						  map_ptr->max_entries, 2);
1888449f08faSAlexei Starovoitov 			insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3,
1889449f08faSAlexei Starovoitov 						    container_of(map_ptr,
1890449f08faSAlexei Starovoitov 								 struct bpf_array,
1891449f08faSAlexei Starovoitov 								 map)->index_mask);
1892449f08faSAlexei Starovoitov 			insn_buf[2] = *insn;
1893449f08faSAlexei Starovoitov 			cnt = 3;
1894449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1895449f08faSAlexei Starovoitov 			if (!new_prog)
1896449f08faSAlexei Starovoitov 				return -ENOMEM;
1897449f08faSAlexei Starovoitov 
1898449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1899449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1900449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1901449f08faSAlexei Starovoitov 			goto next_insn;
1902449f08faSAlexei Starovoitov 		}
1903449f08faSAlexei Starovoitov 
1904449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_timer_set_callback) {
1905449f08faSAlexei Starovoitov 			/* The verifier will process callback_fn as many times as necessary
1906449f08faSAlexei Starovoitov 			 * with different maps and the register states prepared by
1907449f08faSAlexei Starovoitov 			 * set_timer_callback_state will be accurate.
1908449f08faSAlexei Starovoitov 			 *
1909449f08faSAlexei Starovoitov 			 * The following use case is valid:
1910449f08faSAlexei Starovoitov 			 *   map1 is shared by prog1, prog2, prog3.
1911449f08faSAlexei Starovoitov 			 *   prog1 calls bpf_timer_init for some map1 elements
1912449f08faSAlexei Starovoitov 			 *   prog2 calls bpf_timer_set_callback for some map1 elements.
1913449f08faSAlexei Starovoitov 			 *     Those that were not bpf_timer_init-ed will return -EINVAL.
1914449f08faSAlexei Starovoitov 			 *   prog3 calls bpf_timer_start for some map1 elements.
1915449f08faSAlexei Starovoitov 			 *     Those that were not both bpf_timer_init-ed and
1916449f08faSAlexei Starovoitov 			 *     bpf_timer_set_callback-ed will return -EINVAL.
1917449f08faSAlexei Starovoitov 			 */
1918449f08faSAlexei Starovoitov 			struct bpf_insn ld_addrs[2] = {
1919449f08faSAlexei Starovoitov 				BPF_LD_IMM64(BPF_REG_3, (long)prog->aux),
1920449f08faSAlexei Starovoitov 			};
1921449f08faSAlexei Starovoitov 
1922449f08faSAlexei Starovoitov 			insn_buf[0] = ld_addrs[0];
1923449f08faSAlexei Starovoitov 			insn_buf[1] = ld_addrs[1];
1924449f08faSAlexei Starovoitov 			insn_buf[2] = *insn;
1925449f08faSAlexei Starovoitov 			cnt = 3;
1926449f08faSAlexei Starovoitov 
1927449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1928449f08faSAlexei Starovoitov 			if (!new_prog)
1929449f08faSAlexei Starovoitov 				return -ENOMEM;
1930449f08faSAlexei Starovoitov 
1931449f08faSAlexei Starovoitov 			delta    += cnt - 1;
1932449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1933449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
1934449f08faSAlexei Starovoitov 			goto patch_call_imm;
1935449f08faSAlexei Starovoitov 		}
1936449f08faSAlexei Starovoitov 
1937449f08faSAlexei Starovoitov 		/* bpf_per_cpu_ptr() and bpf_this_cpu_ptr() */
1938449f08faSAlexei Starovoitov 		if (env->insn_aux_data[i + delta].call_with_percpu_alloc_ptr) {
1939449f08faSAlexei Starovoitov 			/* patch with 'r1 = *(u64 *)(r1 + 0)' since for percpu data,
1940449f08faSAlexei Starovoitov 			 * bpf_mem_alloc() returns a ptr to the percpu data ptr.
1941449f08faSAlexei Starovoitov 			 */
1942449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0);
1943449f08faSAlexei Starovoitov 			insn_buf[1] = *insn;
1944449f08faSAlexei Starovoitov 			cnt = 2;
1945449f08faSAlexei Starovoitov 
1946449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
1947449f08faSAlexei Starovoitov 			if (!new_prog)
1948449f08faSAlexei Starovoitov 				return -ENOMEM;
1949449f08faSAlexei Starovoitov 
1950449f08faSAlexei Starovoitov 			delta += cnt - 1;
1951449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
1952449f08faSAlexei Starovoitov 			insn = new_prog->insnsi + i + delta;
1953449f08faSAlexei Starovoitov 			goto patch_call_imm;
1954449f08faSAlexei Starovoitov 		}
1955449f08faSAlexei Starovoitov 
1956449f08faSAlexei Starovoitov 		/* BPF_EMIT_CALL() assumptions in some of the map_gen_lookup
1957449f08faSAlexei Starovoitov 		 * and other inlining handlers are currently limited to 64 bit
1958449f08faSAlexei Starovoitov 		 * only.
1959449f08faSAlexei Starovoitov 		 */
1960449f08faSAlexei Starovoitov 		if (prog->jit_requested && BITS_PER_LONG == 64 &&
1961449f08faSAlexei Starovoitov 		    (insn->imm == BPF_FUNC_map_lookup_elem ||
1962449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_update_elem ||
1963449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_delete_elem ||
1964449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_push_elem   ||
1965449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_pop_elem    ||
1966449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_peek_elem   ||
1967449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_redirect_map    ||
1968449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_for_each_map_elem ||
1969449f08faSAlexei Starovoitov 		     insn->imm == BPF_FUNC_map_lookup_percpu_elem)) {
1970449f08faSAlexei Starovoitov 			aux = &env->insn_aux_data[i + delta];
1971449f08faSAlexei Starovoitov 			if (bpf_map_ptr_poisoned(aux))
1972449f08faSAlexei Starovoitov 				goto patch_call_imm;
1973449f08faSAlexei Starovoitov 
1974449f08faSAlexei Starovoitov 			map_ptr = aux->map_ptr_state.map_ptr;
1975449f08faSAlexei Starovoitov 			ops = map_ptr->ops;
1976449f08faSAlexei Starovoitov 			if (insn->imm == BPF_FUNC_map_lookup_elem &&
1977449f08faSAlexei Starovoitov 			    ops->map_gen_lookup) {
1978449f08faSAlexei Starovoitov 				cnt = ops->map_gen_lookup(map_ptr, insn_buf);
1979449f08faSAlexei Starovoitov 				if (cnt == -EOPNOTSUPP)
1980449f08faSAlexei Starovoitov 					goto patch_map_ops_generic;
1981449f08faSAlexei Starovoitov 				if (cnt <= 0 || cnt >= INSN_BUF_SIZE) {
1982449f08faSAlexei Starovoitov 					verifier_bug(env, "%d insns generated for map lookup", cnt);
1983449f08faSAlexei Starovoitov 					return -EFAULT;
1984449f08faSAlexei Starovoitov 				}
1985449f08faSAlexei Starovoitov 
1986449f08faSAlexei Starovoitov 				new_prog = bpf_patch_insn_data(env, i + delta,
1987449f08faSAlexei Starovoitov 							       insn_buf, cnt);
1988449f08faSAlexei Starovoitov 				if (!new_prog)
1989449f08faSAlexei Starovoitov 					return -ENOMEM;
1990449f08faSAlexei Starovoitov 
1991449f08faSAlexei Starovoitov 				delta    += cnt - 1;
1992449f08faSAlexei Starovoitov 				env->prog = prog = new_prog;
1993449f08faSAlexei Starovoitov 				insn      = new_prog->insnsi + i + delta;
1994449f08faSAlexei Starovoitov 				goto next_insn;
1995449f08faSAlexei Starovoitov 			}
1996449f08faSAlexei Starovoitov 
1997449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_lookup_elem,
1998449f08faSAlexei Starovoitov 				     (void *(*)(struct bpf_map *map, void *key))NULL));
1999449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_delete_elem,
2000449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, void *key))NULL));
2001449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_update_elem,
2002449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, void *key, void *value,
2003449f08faSAlexei Starovoitov 					      u64 flags))NULL));
2004449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_push_elem,
2005449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, void *value,
2006449f08faSAlexei Starovoitov 					      u64 flags))NULL));
2007449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_pop_elem,
2008449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, void *value))NULL));
2009449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_peek_elem,
2010449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, void *value))NULL));
2011449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_redirect,
2012449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map, u64 index, u64 flags))NULL));
2013449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_for_each_callback,
2014449f08faSAlexei Starovoitov 				     (long (*)(struct bpf_map *map,
2015449f08faSAlexei Starovoitov 					      bpf_callback_t callback_fn,
2016449f08faSAlexei Starovoitov 					      void *callback_ctx,
2017449f08faSAlexei Starovoitov 					      u64 flags))NULL));
2018449f08faSAlexei Starovoitov 			BUILD_BUG_ON(!__same_type(ops->map_lookup_percpu_elem,
2019449f08faSAlexei Starovoitov 				     (void *(*)(struct bpf_map *map, void *key, u32 cpu))NULL));
2020449f08faSAlexei Starovoitov 
2021449f08faSAlexei Starovoitov patch_map_ops_generic:
2022449f08faSAlexei Starovoitov 			switch (insn->imm) {
2023449f08faSAlexei Starovoitov 			case BPF_FUNC_map_lookup_elem:
2024449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_lookup_elem);
2025449f08faSAlexei Starovoitov 				goto next_insn;
2026449f08faSAlexei Starovoitov 			case BPF_FUNC_map_update_elem:
2027449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_update_elem);
2028449f08faSAlexei Starovoitov 				goto next_insn;
2029449f08faSAlexei Starovoitov 			case BPF_FUNC_map_delete_elem:
2030449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_delete_elem);
2031449f08faSAlexei Starovoitov 				goto next_insn;
2032449f08faSAlexei Starovoitov 			case BPF_FUNC_map_push_elem:
2033449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_push_elem);
2034449f08faSAlexei Starovoitov 				goto next_insn;
2035449f08faSAlexei Starovoitov 			case BPF_FUNC_map_pop_elem:
2036449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_pop_elem);
2037449f08faSAlexei Starovoitov 				goto next_insn;
2038449f08faSAlexei Starovoitov 			case BPF_FUNC_map_peek_elem:
2039449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_peek_elem);
2040449f08faSAlexei Starovoitov 				goto next_insn;
2041449f08faSAlexei Starovoitov 			case BPF_FUNC_redirect_map:
2042449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_redirect);
2043449f08faSAlexei Starovoitov 				goto next_insn;
2044449f08faSAlexei Starovoitov 			case BPF_FUNC_for_each_map_elem:
2045449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_for_each_callback);
2046449f08faSAlexei Starovoitov 				goto next_insn;
2047449f08faSAlexei Starovoitov 			case BPF_FUNC_map_lookup_percpu_elem:
2048449f08faSAlexei Starovoitov 				insn->imm = BPF_CALL_IMM(ops->map_lookup_percpu_elem);
2049449f08faSAlexei Starovoitov 				goto next_insn;
2050449f08faSAlexei Starovoitov 			}
2051449f08faSAlexei Starovoitov 
2052449f08faSAlexei Starovoitov 			goto patch_call_imm;
2053449f08faSAlexei Starovoitov 		}
2054449f08faSAlexei Starovoitov 
2055449f08faSAlexei Starovoitov 		/* Implement bpf_jiffies64 inline. */
2056449f08faSAlexei Starovoitov 		if (prog->jit_requested && BITS_PER_LONG == 64 &&
2057449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_jiffies64) {
2058449f08faSAlexei Starovoitov 			struct bpf_insn ld_jiffies_addr[2] = {
2059449f08faSAlexei Starovoitov 				BPF_LD_IMM64(BPF_REG_0,
2060449f08faSAlexei Starovoitov 					     (unsigned long)&jiffies),
2061449f08faSAlexei Starovoitov 			};
2062449f08faSAlexei Starovoitov 
2063449f08faSAlexei Starovoitov 			insn_buf[0] = ld_jiffies_addr[0];
2064449f08faSAlexei Starovoitov 			insn_buf[1] = ld_jiffies_addr[1];
2065449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_LDX_MEM(BPF_DW, BPF_REG_0,
2066449f08faSAlexei Starovoitov 						  BPF_REG_0, 0);
2067449f08faSAlexei Starovoitov 			cnt = 3;
2068449f08faSAlexei Starovoitov 
2069449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf,
2070449f08faSAlexei Starovoitov 						       cnt);
2071449f08faSAlexei Starovoitov 			if (!new_prog)
2072449f08faSAlexei Starovoitov 				return -ENOMEM;
2073449f08faSAlexei Starovoitov 
2074449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2075449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2076449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2077449f08faSAlexei Starovoitov 			goto next_insn;
2078449f08faSAlexei Starovoitov 		}
2079449f08faSAlexei Starovoitov 
2080449f08faSAlexei Starovoitov #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
2081449f08faSAlexei Starovoitov 		/* Implement bpf_get_smp_processor_id() inline. */
2082449f08faSAlexei Starovoitov 		if (insn->imm == BPF_FUNC_get_smp_processor_id &&
2083449f08faSAlexei Starovoitov 		    bpf_verifier_inlines_helper_call(env, insn->imm)) {
2084449f08faSAlexei Starovoitov 			/* BPF_FUNC_get_smp_processor_id inlining is an
2085449f08faSAlexei Starovoitov 			 * optimization, so if cpu_number is ever
2086449f08faSAlexei Starovoitov 			 * changed in some incompatible and hard to support
2087449f08faSAlexei Starovoitov 			 * way, it's fine to back out this inlining logic
2088449f08faSAlexei Starovoitov 			 */
2089449f08faSAlexei Starovoitov #ifdef CONFIG_SMP
2090449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&cpu_number);
2091449f08faSAlexei Starovoitov 			insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
2092449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
2093449f08faSAlexei Starovoitov 			cnt = 3;
2094449f08faSAlexei Starovoitov #else
2095449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_ALU32_REG(BPF_XOR, BPF_REG_0, BPF_REG_0);
2096449f08faSAlexei Starovoitov 			cnt = 1;
2097449f08faSAlexei Starovoitov #endif
2098449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2099449f08faSAlexei Starovoitov 			if (!new_prog)
2100449f08faSAlexei Starovoitov 				return -ENOMEM;
2101449f08faSAlexei Starovoitov 
2102449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2103449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2104449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2105449f08faSAlexei Starovoitov 			goto next_insn;
2106449f08faSAlexei Starovoitov 		}
2107449f08faSAlexei Starovoitov 
2108449f08faSAlexei Starovoitov 		/* Implement bpf_get_current_task() and bpf_get_current_task_btf() inline. */
2109449f08faSAlexei Starovoitov 		if ((insn->imm == BPF_FUNC_get_current_task || insn->imm == BPF_FUNC_get_current_task_btf) &&
2110449f08faSAlexei Starovoitov 		    bpf_verifier_inlines_helper_call(env, insn->imm)) {
2111449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&current_task);
2112449f08faSAlexei Starovoitov 			insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
2113449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0);
2114449f08faSAlexei Starovoitov 			cnt = 3;
2115449f08faSAlexei Starovoitov 
2116449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2117449f08faSAlexei Starovoitov 			if (!new_prog)
2118449f08faSAlexei Starovoitov 				return -ENOMEM;
2119449f08faSAlexei Starovoitov 
2120449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2121449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2122449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2123449f08faSAlexei Starovoitov 			goto next_insn;
2124449f08faSAlexei Starovoitov 		}
2125449f08faSAlexei Starovoitov #endif
2126449f08faSAlexei Starovoitov 		/* Implement bpf_get_func_arg inline. */
2127449f08faSAlexei Starovoitov 		if (prog_type == BPF_PROG_TYPE_TRACING &&
2128449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_get_func_arg) {
2129449f08faSAlexei Starovoitov 			if (eatype == BPF_TRACE_RAW_TP) {
2130449f08faSAlexei Starovoitov 				int nr_args = btf_type_vlen(prog->aux->attach_func_proto);
2131449f08faSAlexei Starovoitov 
2132449f08faSAlexei Starovoitov 				/* skip 'void *__data' in btf_trace_##name() and save to reg0 */
2133449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, nr_args - 1);
2134449f08faSAlexei Starovoitov 				cnt = 1;
2135449f08faSAlexei Starovoitov 			} else {
2136449f08faSAlexei Starovoitov 				/* Load nr_args from ctx - 8 */
2137449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
2138449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
2139449f08faSAlexei Starovoitov 				cnt = 2;
2140449f08faSAlexei Starovoitov 			}
2141449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_JMP32_REG(BPF_JGE, BPF_REG_2, BPF_REG_0, 6);
2142449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 3);
2143449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1);
2144449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0);
2145449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
2146449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_MOV64_IMM(BPF_REG_0, 0);
2147449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_JMP_A(1);
2148449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL);
2149449f08faSAlexei Starovoitov 
2150449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2151449f08faSAlexei Starovoitov 			if (!new_prog)
2152449f08faSAlexei Starovoitov 				return -ENOMEM;
2153449f08faSAlexei Starovoitov 
2154449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2155449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2156449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2157449f08faSAlexei Starovoitov 			goto next_insn;
2158449f08faSAlexei Starovoitov 		}
2159449f08faSAlexei Starovoitov 
2160449f08faSAlexei Starovoitov 		/* Implement bpf_get_func_ret inline. */
2161449f08faSAlexei Starovoitov 		if (prog_type == BPF_PROG_TYPE_TRACING &&
2162449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_get_func_ret) {
2163449f08faSAlexei Starovoitov 			if (eatype == BPF_TRACE_FEXIT ||
2164449f08faSAlexei Starovoitov 			    eatype == BPF_TRACE_FSESSION ||
2165449f08faSAlexei Starovoitov 			    eatype == BPF_MODIFY_RETURN) {
2166449f08faSAlexei Starovoitov 				/* Load nr_args from ctx - 8 */
2167449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
2168449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
2169449f08faSAlexei Starovoitov 				insn_buf[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3);
2170449f08faSAlexei Starovoitov 				insn_buf[3] = BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1);
2171449f08faSAlexei Starovoitov 				insn_buf[4] = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
2172449f08faSAlexei Starovoitov 				insn_buf[5] = BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0);
2173449f08faSAlexei Starovoitov 				insn_buf[6] = BPF_MOV64_IMM(BPF_REG_0, 0);
2174449f08faSAlexei Starovoitov 				cnt = 7;
2175449f08faSAlexei Starovoitov 			} else {
2176449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, -EOPNOTSUPP);
2177449f08faSAlexei Starovoitov 				cnt = 1;
2178449f08faSAlexei Starovoitov 			}
2179449f08faSAlexei Starovoitov 
2180449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2181449f08faSAlexei Starovoitov 			if (!new_prog)
2182449f08faSAlexei Starovoitov 				return -ENOMEM;
2183449f08faSAlexei Starovoitov 
2184449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2185449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2186449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2187449f08faSAlexei Starovoitov 			goto next_insn;
2188449f08faSAlexei Starovoitov 		}
2189449f08faSAlexei Starovoitov 
2190449f08faSAlexei Starovoitov 		/* Implement get_func_arg_cnt inline. */
2191449f08faSAlexei Starovoitov 		if (prog_type == BPF_PROG_TYPE_TRACING &&
2192449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_get_func_arg_cnt) {
2193449f08faSAlexei Starovoitov 			if (eatype == BPF_TRACE_RAW_TP) {
2194449f08faSAlexei Starovoitov 				int nr_args = btf_type_vlen(prog->aux->attach_func_proto);
2195449f08faSAlexei Starovoitov 
2196449f08faSAlexei Starovoitov 				/* skip 'void *__data' in btf_trace_##name() and save to reg0 */
2197449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, nr_args - 1);
2198449f08faSAlexei Starovoitov 				cnt = 1;
2199449f08faSAlexei Starovoitov 			} else {
2200449f08faSAlexei Starovoitov 				/* Load nr_args from ctx - 8 */
2201449f08faSAlexei Starovoitov 				insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
2202449f08faSAlexei Starovoitov 				insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
2203449f08faSAlexei Starovoitov 				cnt = 2;
2204449f08faSAlexei Starovoitov 			}
2205449f08faSAlexei Starovoitov 
2206449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2207449f08faSAlexei Starovoitov 			if (!new_prog)
2208449f08faSAlexei Starovoitov 				return -ENOMEM;
2209449f08faSAlexei Starovoitov 
2210449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2211449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2212449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2213449f08faSAlexei Starovoitov 			goto next_insn;
2214449f08faSAlexei Starovoitov 		}
2215449f08faSAlexei Starovoitov 
2216449f08faSAlexei Starovoitov 		/* Implement bpf_get_func_ip inline. */
2217449f08faSAlexei Starovoitov 		if (prog_type == BPF_PROG_TYPE_TRACING &&
2218449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_get_func_ip) {
2219449f08faSAlexei Starovoitov 			/* Load IP address from ctx - 16 */
2220449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -16);
2221449f08faSAlexei Starovoitov 
2222449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, 1);
2223449f08faSAlexei Starovoitov 			if (!new_prog)
2224449f08faSAlexei Starovoitov 				return -ENOMEM;
2225449f08faSAlexei Starovoitov 
2226449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2227449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2228449f08faSAlexei Starovoitov 			goto next_insn;
2229449f08faSAlexei Starovoitov 		}
2230449f08faSAlexei Starovoitov 
2231449f08faSAlexei Starovoitov 		/* Implement bpf_get_branch_snapshot inline. */
2232449f08faSAlexei Starovoitov 		if (IS_ENABLED(CONFIG_PERF_EVENTS) &&
2233449f08faSAlexei Starovoitov 		    prog->jit_requested && BITS_PER_LONG == 64 &&
2234449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_get_branch_snapshot) {
2235449f08faSAlexei Starovoitov 			/* We are dealing with the following func protos:
2236449f08faSAlexei Starovoitov 			 * u64 bpf_get_branch_snapshot(void *buf, u32 size, u64 flags);
2237449f08faSAlexei Starovoitov 			 * int perf_snapshot_branch_stack(struct perf_branch_entry *entries, u32 cnt);
2238449f08faSAlexei Starovoitov 			 */
2239449f08faSAlexei Starovoitov 			const u32 br_entry_size = sizeof(struct perf_branch_entry);
2240449f08faSAlexei Starovoitov 
2241449f08faSAlexei Starovoitov 			/* struct perf_branch_entry is part of UAPI and is
2242449f08faSAlexei Starovoitov 			 * used as an array element, so extremely unlikely to
2243449f08faSAlexei Starovoitov 			 * ever grow or shrink
2244449f08faSAlexei Starovoitov 			 */
2245449f08faSAlexei Starovoitov 			BUILD_BUG_ON(br_entry_size != 24);
2246449f08faSAlexei Starovoitov 
2247449f08faSAlexei Starovoitov 			/* if (unlikely(flags)) return -EINVAL */
2248449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 0, 7);
2249449f08faSAlexei Starovoitov 
2250449f08faSAlexei Starovoitov 			/* Transform size (bytes) into number of entries (cnt = size / 24).
2251449f08faSAlexei Starovoitov 			 * But to avoid expensive division instruction, we implement
2252449f08faSAlexei Starovoitov 			 * divide-by-3 through multiplication, followed by further
2253449f08faSAlexei Starovoitov 			 * division by 8 through 3-bit right shift.
2254449f08faSAlexei Starovoitov 			 * Refer to book "Hacker's Delight, 2nd ed." by Henry S. Warren, Jr.,
2255449f08faSAlexei Starovoitov 			 * p. 227, chapter "Unsigned Division by 3" for details and proofs.
2256449f08faSAlexei Starovoitov 			 *
2257449f08faSAlexei Starovoitov 			 * N / 3 <=> M * N / 2^33, where M = (2^33 + 1) / 3 = 0xaaaaaaab.
2258449f08faSAlexei Starovoitov 			 */
2259449f08faSAlexei Starovoitov 			insn_buf[1] = BPF_MOV32_IMM(BPF_REG_0, 0xaaaaaaab);
2260449f08faSAlexei Starovoitov 			insn_buf[2] = BPF_ALU64_REG(BPF_MUL, BPF_REG_2, BPF_REG_0);
2261449f08faSAlexei Starovoitov 			insn_buf[3] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_2, 36);
2262449f08faSAlexei Starovoitov 
2263449f08faSAlexei Starovoitov 			/* call perf_snapshot_branch_stack implementation */
2264449f08faSAlexei Starovoitov 			insn_buf[4] = BPF_EMIT_CALL(static_call_query(perf_snapshot_branch_stack));
2265449f08faSAlexei Starovoitov 			/* if (entry_cnt == 0) return -ENOENT */
2266449f08faSAlexei Starovoitov 			insn_buf[5] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4);
2267449f08faSAlexei Starovoitov 			/* return entry_cnt * sizeof(struct perf_branch_entry) */
2268449f08faSAlexei Starovoitov 			insn_buf[6] = BPF_ALU32_IMM(BPF_MUL, BPF_REG_0, br_entry_size);
2269449f08faSAlexei Starovoitov 			insn_buf[7] = BPF_JMP_A(3);
2270449f08faSAlexei Starovoitov 			/* return -EINVAL; */
2271449f08faSAlexei Starovoitov 			insn_buf[8] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL);
2272449f08faSAlexei Starovoitov 			insn_buf[9] = BPF_JMP_A(1);
2273449f08faSAlexei Starovoitov 			/* return -ENOENT; */
2274449f08faSAlexei Starovoitov 			insn_buf[10] = BPF_MOV64_IMM(BPF_REG_0, -ENOENT);
2275449f08faSAlexei Starovoitov 			cnt = 11;
2276449f08faSAlexei Starovoitov 
2277449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2278449f08faSAlexei Starovoitov 			if (!new_prog)
2279449f08faSAlexei Starovoitov 				return -ENOMEM;
2280449f08faSAlexei Starovoitov 
2281449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2282449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2283449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2284449f08faSAlexei Starovoitov 			goto next_insn;
2285449f08faSAlexei Starovoitov 		}
2286449f08faSAlexei Starovoitov 
2287449f08faSAlexei Starovoitov 		/* Implement bpf_kptr_xchg inline */
2288449f08faSAlexei Starovoitov 		if (prog->jit_requested && BITS_PER_LONG == 64 &&
2289449f08faSAlexei Starovoitov 		    insn->imm == BPF_FUNC_kptr_xchg &&
2290449f08faSAlexei Starovoitov 		    bpf_jit_supports_ptr_xchg()) {
2291449f08faSAlexei Starovoitov 			insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_2);
2292449f08faSAlexei Starovoitov 			insn_buf[1] = BPF_ATOMIC_OP(BPF_DW, BPF_XCHG, BPF_REG_1, BPF_REG_0, 0);
2293449f08faSAlexei Starovoitov 			cnt = 2;
2294449f08faSAlexei Starovoitov 
2295449f08faSAlexei Starovoitov 			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
2296449f08faSAlexei Starovoitov 			if (!new_prog)
2297449f08faSAlexei Starovoitov 				return -ENOMEM;
2298449f08faSAlexei Starovoitov 
2299449f08faSAlexei Starovoitov 			delta    += cnt - 1;
2300449f08faSAlexei Starovoitov 			env->prog = prog = new_prog;
2301449f08faSAlexei Starovoitov 			insn      = new_prog->insnsi + i + delta;
2302449f08faSAlexei Starovoitov 			goto next_insn;
2303449f08faSAlexei Starovoitov 		}
2304449f08faSAlexei Starovoitov patch_call_imm:
2305449f08faSAlexei Starovoitov 		fn = env->ops->get_func_proto(insn->imm, env->prog);
2306449f08faSAlexei Starovoitov 		/* all functions that have prototype and verifier allowed
2307449f08faSAlexei Starovoitov 		 * programs to call them, must be real in-kernel functions
2308449f08faSAlexei Starovoitov 		 */
2309449f08faSAlexei Starovoitov 		if (!fn->func) {
2310449f08faSAlexei Starovoitov 			verifier_bug(env,
2311449f08faSAlexei Starovoitov 				     "not inlined functions %s#%d is missing func",
2312449f08faSAlexei Starovoitov 				     func_id_name(insn->imm), insn->imm);
2313449f08faSAlexei Starovoitov 			return -EFAULT;
2314449f08faSAlexei Starovoitov 		}
2315449f08faSAlexei Starovoitov 		insn->imm = fn->func - __bpf_call_base;
2316449f08faSAlexei Starovoitov next_insn:
2317449f08faSAlexei Starovoitov 		if (subprogs[cur_subprog + 1].start == i + delta + 1) {
2318449f08faSAlexei Starovoitov 			subprogs[cur_subprog].stack_depth += stack_depth_extra;
2319449f08faSAlexei Starovoitov 			subprogs[cur_subprog].stack_extra = stack_depth_extra;
2320449f08faSAlexei Starovoitov 
2321449f08faSAlexei Starovoitov 			stack_depth = subprogs[cur_subprog].stack_depth;
2322449f08faSAlexei Starovoitov 			if (stack_depth > MAX_BPF_STACK && !prog->jit_requested) {
2323449f08faSAlexei Starovoitov 				verbose(env, "stack size %d(extra %d) is too large\n",
2324449f08faSAlexei Starovoitov 					stack_depth, stack_depth_extra);
2325449f08faSAlexei Starovoitov 				return -EINVAL;
2326449f08faSAlexei Starovoitov 			}
2327449f08faSAlexei Starovoitov 			cur_subprog++;
2328449f08faSAlexei Starovoitov 			stack_depth = subprogs[cur_subprog].stack_depth;
2329449f08faSAlexei Starovoitov 			stack_depth_extra = 0;
2330449f08faSAlexei Starovoitov 		}
2331449f08faSAlexei Starovoitov 		i++;
2332449f08faSAlexei Starovoitov 		insn++;
2333449f08faSAlexei Starovoitov 	}
2334449f08faSAlexei Starovoitov 
2335449f08faSAlexei Starovoitov 	env->prog->aux->stack_depth = subprogs[0].stack_depth;
2336449f08faSAlexei Starovoitov 	for (i = 0; i < env->subprog_cnt; i++) {
2337449f08faSAlexei Starovoitov 		int delta = bpf_jit_supports_timed_may_goto() ? 2 : 1;
2338449f08faSAlexei Starovoitov 		int subprog_start = subprogs[i].start;
2339449f08faSAlexei Starovoitov 		int stack_slots = subprogs[i].stack_extra / 8;
2340449f08faSAlexei Starovoitov 		int slots = delta, cnt = 0;
2341449f08faSAlexei Starovoitov 
2342449f08faSAlexei Starovoitov 		if (!stack_slots)
2343449f08faSAlexei Starovoitov 			continue;
2344449f08faSAlexei Starovoitov 		/* We need two slots in case timed may_goto is supported. */
2345449f08faSAlexei Starovoitov 		if (stack_slots > slots) {
2346449f08faSAlexei Starovoitov 			verifier_bug(env, "stack_slots supports may_goto only");
2347449f08faSAlexei Starovoitov 			return -EFAULT;
2348449f08faSAlexei Starovoitov 		}
2349449f08faSAlexei Starovoitov 
2350449f08faSAlexei Starovoitov 		stack_depth = subprogs[i].stack_depth;
2351449f08faSAlexei Starovoitov 		if (bpf_jit_supports_timed_may_goto()) {
2352449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth,
2353449f08faSAlexei Starovoitov 						     BPF_MAX_TIMED_LOOPS);
2354449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth + 8, 0);
2355449f08faSAlexei Starovoitov 		} else {
2356449f08faSAlexei Starovoitov 			/* Add ST insn to subprog prologue to init extra stack */
2357449f08faSAlexei Starovoitov 			insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth,
2358449f08faSAlexei Starovoitov 						     BPF_MAX_LOOPS);
2359449f08faSAlexei Starovoitov 		}
2360449f08faSAlexei Starovoitov 		/* Copy first actual insn to preserve it */
2361449f08faSAlexei Starovoitov 		insn_buf[cnt++] = env->prog->insnsi[subprog_start];
2362449f08faSAlexei Starovoitov 
2363449f08faSAlexei Starovoitov 		new_prog = bpf_patch_insn_data(env, subprog_start, insn_buf, cnt);
2364449f08faSAlexei Starovoitov 		if (!new_prog)
2365449f08faSAlexei Starovoitov 			return -ENOMEM;
2366449f08faSAlexei Starovoitov 		env->prog = prog = new_prog;
2367449f08faSAlexei Starovoitov 		/*
2368449f08faSAlexei Starovoitov 		 * If may_goto is a first insn of a prog there could be a jmp
2369449f08faSAlexei Starovoitov 		 * insn that points to it, hence adjust all such jmps to point
2370449f08faSAlexei Starovoitov 		 * to insn after BPF_ST that inits may_goto count.
2371449f08faSAlexei Starovoitov 		 * Adjustment will succeed because bpf_patch_insn_data() didn't fail.
2372449f08faSAlexei Starovoitov 		 */
2373449f08faSAlexei Starovoitov 		WARN_ON(adjust_jmp_off(env->prog, subprog_start, delta));
2374449f08faSAlexei Starovoitov 	}
2375449f08faSAlexei Starovoitov 
2376449f08faSAlexei Starovoitov 	/* Since poke tab is now finalized, publish aux to tracker. */
2377449f08faSAlexei Starovoitov 	for (i = 0; i < prog->aux->size_poke_tab; i++) {
2378449f08faSAlexei Starovoitov 		map_ptr = prog->aux->poke_tab[i].tail_call.map;
2379449f08faSAlexei Starovoitov 		if (!map_ptr->ops->map_poke_track ||
2380449f08faSAlexei Starovoitov 		    !map_ptr->ops->map_poke_untrack ||
2381449f08faSAlexei Starovoitov 		    !map_ptr->ops->map_poke_run) {
2382449f08faSAlexei Starovoitov 			verifier_bug(env, "poke tab is misconfigured");
2383449f08faSAlexei Starovoitov 			return -EFAULT;
2384449f08faSAlexei Starovoitov 		}
2385449f08faSAlexei Starovoitov 
2386449f08faSAlexei Starovoitov 		ret = map_ptr->ops->map_poke_track(map_ptr, prog->aux);
2387449f08faSAlexei Starovoitov 		if (ret < 0) {
2388449f08faSAlexei Starovoitov 			verbose(env, "tracking tail call prog failed\n");
2389449f08faSAlexei Starovoitov 			return ret;
2390449f08faSAlexei Starovoitov 		}
2391449f08faSAlexei Starovoitov 	}
2392449f08faSAlexei Starovoitov 
2393449f08faSAlexei Starovoitov 	ret = sort_kfunc_descs_by_imm_off(env);
2394449f08faSAlexei Starovoitov 	if (ret)
2395449f08faSAlexei Starovoitov 		return ret;
2396449f08faSAlexei Starovoitov 
2397449f08faSAlexei Starovoitov 	return 0;
2398449f08faSAlexei Starovoitov }
2399449f08faSAlexei Starovoitov 
2400449f08faSAlexei Starovoitov static struct bpf_prog *inline_bpf_loop(struct bpf_verifier_env *env,
2401449f08faSAlexei Starovoitov 					int position,
2402449f08faSAlexei Starovoitov 					s32 stack_base,
2403449f08faSAlexei Starovoitov 					u32 callback_subprogno,
2404449f08faSAlexei Starovoitov 					u32 *total_cnt)
2405449f08faSAlexei Starovoitov {
2406449f08faSAlexei Starovoitov 	s32 r6_offset = stack_base + 0 * BPF_REG_SIZE;
2407449f08faSAlexei Starovoitov 	s32 r7_offset = stack_base + 1 * BPF_REG_SIZE;
2408449f08faSAlexei Starovoitov 	s32 r8_offset = stack_base + 2 * BPF_REG_SIZE;
2409449f08faSAlexei Starovoitov 	int reg_loop_max = BPF_REG_6;
2410449f08faSAlexei Starovoitov 	int reg_loop_cnt = BPF_REG_7;
2411449f08faSAlexei Starovoitov 	int reg_loop_ctx = BPF_REG_8;
2412449f08faSAlexei Starovoitov 
2413449f08faSAlexei Starovoitov 	struct bpf_insn *insn_buf = env->insn_buf;
2414449f08faSAlexei Starovoitov 	struct bpf_prog *new_prog;
2415449f08faSAlexei Starovoitov 	u32 callback_start;
2416449f08faSAlexei Starovoitov 	u32 call_insn_offset;
2417449f08faSAlexei Starovoitov 	s32 callback_offset;
2418449f08faSAlexei Starovoitov 	u32 cnt = 0;
2419449f08faSAlexei Starovoitov 
2420449f08faSAlexei Starovoitov 	/* This represents an inlined version of bpf_iter.c:bpf_loop,
2421449f08faSAlexei Starovoitov 	 * be careful to modify this code in sync.
2422449f08faSAlexei Starovoitov 	 */
2423449f08faSAlexei Starovoitov 
2424449f08faSAlexei Starovoitov 	/* Return error and jump to the end of the patch if
2425449f08faSAlexei Starovoitov 	 * expected number of iterations is too big.
2426449f08faSAlexei Starovoitov 	 */
2427449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_JMP_IMM(BPF_JLE, BPF_REG_1, BPF_MAX_LOOPS, 2);
2428449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV32_IMM(BPF_REG_0, -E2BIG);
2429449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_JMP_IMM(BPF_JA, 0, 0, 16);
2430449f08faSAlexei Starovoitov 	/* spill R6, R7, R8 to use these as loop vars */
2431449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, r6_offset);
2432449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7, r7_offset);
2433449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_8, r8_offset);
2434449f08faSAlexei Starovoitov 	/* initialize loop vars */
2435449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV64_REG(reg_loop_max, BPF_REG_1);
2436449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV32_IMM(reg_loop_cnt, 0);
2437449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV64_REG(reg_loop_ctx, BPF_REG_3);
2438449f08faSAlexei Starovoitov 	/* loop header,
2439449f08faSAlexei Starovoitov 	 * if reg_loop_cnt >= reg_loop_max skip the loop body
2440449f08faSAlexei Starovoitov 	 */
2441449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_JMP_REG(BPF_JGE, reg_loop_cnt, reg_loop_max, 5);
2442449f08faSAlexei Starovoitov 	/* callback call,
2443449f08faSAlexei Starovoitov 	 * correct callback offset would be set after patching
2444449f08faSAlexei Starovoitov 	 */
2445449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV64_REG(BPF_REG_1, reg_loop_cnt);
2446449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV64_REG(BPF_REG_2, reg_loop_ctx);
2447449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_CALL_REL(0);
2448449f08faSAlexei Starovoitov 	/* increment loop counter */
2449449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_ALU64_IMM(BPF_ADD, reg_loop_cnt, 1);
2450449f08faSAlexei Starovoitov 	/* jump to loop header if callback returned 0 */
2451449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, -6);
2452449f08faSAlexei Starovoitov 	/* return value of bpf_loop,
2453449f08faSAlexei Starovoitov 	 * set R0 to the number of iterations
2454449f08faSAlexei Starovoitov 	 */
2455449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_MOV64_REG(BPF_REG_0, reg_loop_cnt);
2456449f08faSAlexei Starovoitov 	/* restore original values of R6, R7, R8 */
2457449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, r6_offset);
2458449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_10, r7_offset);
2459449f08faSAlexei Starovoitov 	insn_buf[cnt++] = BPF_LDX_MEM(BPF_DW, BPF_REG_8, BPF_REG_10, r8_offset);
2460449f08faSAlexei Starovoitov 
2461449f08faSAlexei Starovoitov 	*total_cnt = cnt;
2462449f08faSAlexei Starovoitov 	new_prog = bpf_patch_insn_data(env, position, insn_buf, cnt);
2463449f08faSAlexei Starovoitov 	if (!new_prog)
2464449f08faSAlexei Starovoitov 		return new_prog;
2465449f08faSAlexei Starovoitov 
2466449f08faSAlexei Starovoitov 	/* callback start is known only after patching */
2467449f08faSAlexei Starovoitov 	callback_start = env->subprog_info[callback_subprogno].start;
2468449f08faSAlexei Starovoitov 	/* Note: insn_buf[12] is an offset of BPF_CALL_REL instruction */
2469449f08faSAlexei Starovoitov 	call_insn_offset = position + 12;
2470449f08faSAlexei Starovoitov 	callback_offset = callback_start - call_insn_offset - 1;
2471449f08faSAlexei Starovoitov 	new_prog->insnsi[call_insn_offset].imm = callback_offset;
2472449f08faSAlexei Starovoitov 
2473449f08faSAlexei Starovoitov 	return new_prog;
2474449f08faSAlexei Starovoitov }
2475449f08faSAlexei Starovoitov 
2476449f08faSAlexei Starovoitov static bool is_bpf_loop_call(struct bpf_insn *insn)
2477449f08faSAlexei Starovoitov {
2478449f08faSAlexei Starovoitov 	return insn->code == (BPF_JMP | BPF_CALL) &&
2479449f08faSAlexei Starovoitov 		insn->src_reg == 0 &&
2480449f08faSAlexei Starovoitov 		insn->imm == BPF_FUNC_loop;
2481449f08faSAlexei Starovoitov }
2482449f08faSAlexei Starovoitov 
2483449f08faSAlexei Starovoitov /* For all sub-programs in the program (including main) check
2484449f08faSAlexei Starovoitov  * insn_aux_data to see if there are bpf_loop calls that require
2485449f08faSAlexei Starovoitov  * inlining. If such calls are found the calls are replaced with a
2486449f08faSAlexei Starovoitov  * sequence of instructions produced by `inline_bpf_loop` function and
2487449f08faSAlexei Starovoitov  * subprog stack_depth is increased by the size of 3 registers.
2488449f08faSAlexei Starovoitov  * This stack space is used to spill values of the R6, R7, R8.  These
2489449f08faSAlexei Starovoitov  * registers are used to store the loop bound, counter and context
2490449f08faSAlexei Starovoitov  * variables.
2491449f08faSAlexei Starovoitov  */
2492449f08faSAlexei Starovoitov int bpf_optimize_bpf_loop(struct bpf_verifier_env *env)
2493449f08faSAlexei Starovoitov {
2494449f08faSAlexei Starovoitov 	struct bpf_subprog_info *subprogs = env->subprog_info;
2495449f08faSAlexei Starovoitov 	int i, cur_subprog = 0, cnt, delta = 0;
2496449f08faSAlexei Starovoitov 	struct bpf_insn *insn = env->prog->insnsi;
2497449f08faSAlexei Starovoitov 	int insn_cnt = env->prog->len;
2498449f08faSAlexei Starovoitov 	u16 stack_depth = subprogs[cur_subprog].stack_depth;
2499449f08faSAlexei Starovoitov 	u16 stack_depth_roundup = round_up(stack_depth, 8) - stack_depth;
2500449f08faSAlexei Starovoitov 	u16 stack_depth_extra = 0;
2501449f08faSAlexei Starovoitov 
2502449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++, insn++) {
2503449f08faSAlexei Starovoitov 		struct bpf_loop_inline_state *inline_state =
2504449f08faSAlexei Starovoitov 			&env->insn_aux_data[i + delta].loop_inline_state;
2505449f08faSAlexei Starovoitov 
2506449f08faSAlexei Starovoitov 		if (is_bpf_loop_call(insn) && inline_state->fit_for_inline) {
2507449f08faSAlexei Starovoitov 			struct bpf_prog *new_prog;
2508449f08faSAlexei Starovoitov 
2509449f08faSAlexei Starovoitov 			stack_depth_extra = BPF_REG_SIZE * 3 + stack_depth_roundup;
2510449f08faSAlexei Starovoitov 			new_prog = inline_bpf_loop(env,
2511449f08faSAlexei Starovoitov 						   i + delta,
2512449f08faSAlexei Starovoitov 						   -(stack_depth + stack_depth_extra),
2513449f08faSAlexei Starovoitov 						   inline_state->callback_subprogno,
2514449f08faSAlexei Starovoitov 						   &cnt);
2515449f08faSAlexei Starovoitov 			if (!new_prog)
2516449f08faSAlexei Starovoitov 				return -ENOMEM;
2517449f08faSAlexei Starovoitov 
2518449f08faSAlexei Starovoitov 			delta     += cnt - 1;
2519449f08faSAlexei Starovoitov 			env->prog  = new_prog;
2520449f08faSAlexei Starovoitov 			insn       = new_prog->insnsi + i + delta;
2521449f08faSAlexei Starovoitov 		}
2522449f08faSAlexei Starovoitov 
2523449f08faSAlexei Starovoitov 		if (subprogs[cur_subprog + 1].start == i + delta + 1) {
2524449f08faSAlexei Starovoitov 			subprogs[cur_subprog].stack_depth += stack_depth_extra;
2525449f08faSAlexei Starovoitov 			cur_subprog++;
2526449f08faSAlexei Starovoitov 			stack_depth = subprogs[cur_subprog].stack_depth;
2527449f08faSAlexei Starovoitov 			stack_depth_roundup = round_up(stack_depth, 8) - stack_depth;
2528449f08faSAlexei Starovoitov 			stack_depth_extra = 0;
2529449f08faSAlexei Starovoitov 		}
2530449f08faSAlexei Starovoitov 	}
2531449f08faSAlexei Starovoitov 
2532449f08faSAlexei Starovoitov 	env->prog->aux->stack_depth = env->subprog_info[0].stack_depth;
2533449f08faSAlexei Starovoitov 
2534449f08faSAlexei Starovoitov 	return 0;
2535449f08faSAlexei Starovoitov }
2536449f08faSAlexei Starovoitov 
2537449f08faSAlexei Starovoitov /* Remove unnecessary spill/fill pairs, members of fastcall pattern,
2538449f08faSAlexei Starovoitov  * adjust subprograms stack depth when possible.
2539449f08faSAlexei Starovoitov  */
2540449f08faSAlexei Starovoitov int bpf_remove_fastcall_spills_fills(struct bpf_verifier_env *env)
2541449f08faSAlexei Starovoitov {
2542449f08faSAlexei Starovoitov 	struct bpf_subprog_info *subprog = env->subprog_info;
2543449f08faSAlexei Starovoitov 	struct bpf_insn_aux_data *aux = env->insn_aux_data;
2544449f08faSAlexei Starovoitov 	struct bpf_insn *insn = env->prog->insnsi;
2545449f08faSAlexei Starovoitov 	int insn_cnt = env->prog->len;
2546449f08faSAlexei Starovoitov 	u32 spills_num;
2547449f08faSAlexei Starovoitov 	bool modified = false;
2548449f08faSAlexei Starovoitov 	int i, j;
2549449f08faSAlexei Starovoitov 
2550449f08faSAlexei Starovoitov 	for (i = 0; i < insn_cnt; i++, insn++) {
2551449f08faSAlexei Starovoitov 		if (aux[i].fastcall_spills_num > 0) {
2552449f08faSAlexei Starovoitov 			spills_num = aux[i].fastcall_spills_num;
2553449f08faSAlexei Starovoitov 			/* NOPs would be removed by opt_remove_nops() */
2554449f08faSAlexei Starovoitov 			for (j = 1; j <= spills_num; ++j) {
2555449f08faSAlexei Starovoitov 				*(insn - j) = NOP;
2556449f08faSAlexei Starovoitov 				*(insn + j) = NOP;
2557449f08faSAlexei Starovoitov 			}
2558449f08faSAlexei Starovoitov 			modified = true;
2559449f08faSAlexei Starovoitov 		}
2560449f08faSAlexei Starovoitov 		if ((subprog + 1)->start == i + 1) {
2561449f08faSAlexei Starovoitov 			if (modified && !subprog->keep_fastcall_stack)
2562449f08faSAlexei Starovoitov 				subprog->stack_depth = -subprog->fastcall_stack_off;
2563449f08faSAlexei Starovoitov 			subprog++;
2564449f08faSAlexei Starovoitov 			modified = false;
2565449f08faSAlexei Starovoitov 		}
2566449f08faSAlexei Starovoitov 	}
2567449f08faSAlexei Starovoitov 
2568449f08faSAlexei Starovoitov 	return 0;
2569449f08faSAlexei Starovoitov }
2570449f08faSAlexei Starovoitov 
2571