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