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)¤t_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