1*b4ce5923SAnton Protopopov // SPDX-License-Identifier: GPL-2.0-only 2*b4ce5923SAnton Protopopov /* Copyright (c) 2025 Isovalent */ 3*b4ce5923SAnton Protopopov 4*b4ce5923SAnton Protopopov #include <linux/bpf.h> 5*b4ce5923SAnton Protopopov 6*b4ce5923SAnton Protopopov struct bpf_insn_array { 7*b4ce5923SAnton Protopopov struct bpf_map map; 8*b4ce5923SAnton Protopopov atomic_t used; 9*b4ce5923SAnton Protopopov long *ips; 10*b4ce5923SAnton Protopopov DECLARE_FLEX_ARRAY(struct bpf_insn_array_value, values); 11*b4ce5923SAnton Protopopov }; 12*b4ce5923SAnton Protopopov 13*b4ce5923SAnton Protopopov #define cast_insn_array(MAP_PTR) \ 14*b4ce5923SAnton Protopopov container_of((MAP_PTR), struct bpf_insn_array, map) 15*b4ce5923SAnton Protopopov 16*b4ce5923SAnton Protopopov #define INSN_DELETED ((u32)-1) 17*b4ce5923SAnton Protopopov 18*b4ce5923SAnton Protopopov static inline u64 insn_array_alloc_size(u32 max_entries) 19*b4ce5923SAnton Protopopov { 20*b4ce5923SAnton Protopopov const u64 base_size = sizeof(struct bpf_insn_array); 21*b4ce5923SAnton Protopopov const u64 entry_size = sizeof(struct bpf_insn_array_value); 22*b4ce5923SAnton Protopopov 23*b4ce5923SAnton Protopopov return base_size + max_entries * (entry_size + sizeof(long)); 24*b4ce5923SAnton Protopopov } 25*b4ce5923SAnton Protopopov 26*b4ce5923SAnton Protopopov static int insn_array_alloc_check(union bpf_attr *attr) 27*b4ce5923SAnton Protopopov { 28*b4ce5923SAnton Protopopov u32 value_size = sizeof(struct bpf_insn_array_value); 29*b4ce5923SAnton Protopopov 30*b4ce5923SAnton Protopopov if (attr->max_entries == 0 || attr->key_size != 4 || 31*b4ce5923SAnton Protopopov attr->value_size != value_size || attr->map_flags != 0) 32*b4ce5923SAnton Protopopov return -EINVAL; 33*b4ce5923SAnton Protopopov 34*b4ce5923SAnton Protopopov return 0; 35*b4ce5923SAnton Protopopov } 36*b4ce5923SAnton Protopopov 37*b4ce5923SAnton Protopopov static void insn_array_free(struct bpf_map *map) 38*b4ce5923SAnton Protopopov { 39*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 40*b4ce5923SAnton Protopopov 41*b4ce5923SAnton Protopopov bpf_map_area_free(insn_array); 42*b4ce5923SAnton Protopopov } 43*b4ce5923SAnton Protopopov 44*b4ce5923SAnton Protopopov static struct bpf_map *insn_array_alloc(union bpf_attr *attr) 45*b4ce5923SAnton Protopopov { 46*b4ce5923SAnton Protopopov u64 size = insn_array_alloc_size(attr->max_entries); 47*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array; 48*b4ce5923SAnton Protopopov 49*b4ce5923SAnton Protopopov insn_array = bpf_map_area_alloc(size, NUMA_NO_NODE); 50*b4ce5923SAnton Protopopov if (!insn_array) 51*b4ce5923SAnton Protopopov return ERR_PTR(-ENOMEM); 52*b4ce5923SAnton Protopopov 53*b4ce5923SAnton Protopopov /* ips are allocated right after the insn_array->values[] array */ 54*b4ce5923SAnton Protopopov insn_array->ips = (void *)&insn_array->values[attr->max_entries]; 55*b4ce5923SAnton Protopopov 56*b4ce5923SAnton Protopopov bpf_map_init_from_attr(&insn_array->map, attr); 57*b4ce5923SAnton Protopopov 58*b4ce5923SAnton Protopopov return &insn_array->map; 59*b4ce5923SAnton Protopopov } 60*b4ce5923SAnton Protopopov 61*b4ce5923SAnton Protopopov static void *insn_array_lookup_elem(struct bpf_map *map, void *key) 62*b4ce5923SAnton Protopopov { 63*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 64*b4ce5923SAnton Protopopov u32 index = *(u32 *)key; 65*b4ce5923SAnton Protopopov 66*b4ce5923SAnton Protopopov if (unlikely(index >= insn_array->map.max_entries)) 67*b4ce5923SAnton Protopopov return NULL; 68*b4ce5923SAnton Protopopov 69*b4ce5923SAnton Protopopov return &insn_array->values[index]; 70*b4ce5923SAnton Protopopov } 71*b4ce5923SAnton Protopopov 72*b4ce5923SAnton Protopopov static long insn_array_update_elem(struct bpf_map *map, void *key, void *value, u64 map_flags) 73*b4ce5923SAnton Protopopov { 74*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 75*b4ce5923SAnton Protopopov u32 index = *(u32 *)key; 76*b4ce5923SAnton Protopopov struct bpf_insn_array_value val = {}; 77*b4ce5923SAnton Protopopov 78*b4ce5923SAnton Protopopov if (unlikely(index >= insn_array->map.max_entries)) 79*b4ce5923SAnton Protopopov return -E2BIG; 80*b4ce5923SAnton Protopopov 81*b4ce5923SAnton Protopopov if (unlikely(map_flags & BPF_NOEXIST)) 82*b4ce5923SAnton Protopopov return -EEXIST; 83*b4ce5923SAnton Protopopov 84*b4ce5923SAnton Protopopov copy_map_value(map, &val, value); 85*b4ce5923SAnton Protopopov if (val.jitted_off || val.xlated_off) 86*b4ce5923SAnton Protopopov return -EINVAL; 87*b4ce5923SAnton Protopopov 88*b4ce5923SAnton Protopopov insn_array->values[index].orig_off = val.orig_off; 89*b4ce5923SAnton Protopopov 90*b4ce5923SAnton Protopopov return 0; 91*b4ce5923SAnton Protopopov } 92*b4ce5923SAnton Protopopov 93*b4ce5923SAnton Protopopov static long insn_array_delete_elem(struct bpf_map *map, void *key) 94*b4ce5923SAnton Protopopov { 95*b4ce5923SAnton Protopopov return -EINVAL; 96*b4ce5923SAnton Protopopov } 97*b4ce5923SAnton Protopopov 98*b4ce5923SAnton Protopopov static int insn_array_check_btf(const struct bpf_map *map, 99*b4ce5923SAnton Protopopov const struct btf *btf, 100*b4ce5923SAnton Protopopov const struct btf_type *key_type, 101*b4ce5923SAnton Protopopov const struct btf_type *value_type) 102*b4ce5923SAnton Protopopov { 103*b4ce5923SAnton Protopopov if (!btf_type_is_i32(key_type)) 104*b4ce5923SAnton Protopopov return -EINVAL; 105*b4ce5923SAnton Protopopov 106*b4ce5923SAnton Protopopov if (!btf_type_is_i64(value_type)) 107*b4ce5923SAnton Protopopov return -EINVAL; 108*b4ce5923SAnton Protopopov 109*b4ce5923SAnton Protopopov return 0; 110*b4ce5923SAnton Protopopov } 111*b4ce5923SAnton Protopopov 112*b4ce5923SAnton Protopopov static u64 insn_array_mem_usage(const struct bpf_map *map) 113*b4ce5923SAnton Protopopov { 114*b4ce5923SAnton Protopopov return insn_array_alloc_size(map->max_entries); 115*b4ce5923SAnton Protopopov } 116*b4ce5923SAnton Protopopov 117*b4ce5923SAnton Protopopov BTF_ID_LIST_SINGLE(insn_array_btf_ids, struct, bpf_insn_array) 118*b4ce5923SAnton Protopopov 119*b4ce5923SAnton Protopopov const struct bpf_map_ops insn_array_map_ops = { 120*b4ce5923SAnton Protopopov .map_alloc_check = insn_array_alloc_check, 121*b4ce5923SAnton Protopopov .map_alloc = insn_array_alloc, 122*b4ce5923SAnton Protopopov .map_free = insn_array_free, 123*b4ce5923SAnton Protopopov .map_get_next_key = bpf_array_get_next_key, 124*b4ce5923SAnton Protopopov .map_lookup_elem = insn_array_lookup_elem, 125*b4ce5923SAnton Protopopov .map_update_elem = insn_array_update_elem, 126*b4ce5923SAnton Protopopov .map_delete_elem = insn_array_delete_elem, 127*b4ce5923SAnton Protopopov .map_check_btf = insn_array_check_btf, 128*b4ce5923SAnton Protopopov .map_mem_usage = insn_array_mem_usage, 129*b4ce5923SAnton Protopopov .map_btf_id = &insn_array_btf_ids[0], 130*b4ce5923SAnton Protopopov }; 131*b4ce5923SAnton Protopopov 132*b4ce5923SAnton Protopopov static inline bool is_frozen(struct bpf_map *map) 133*b4ce5923SAnton Protopopov { 134*b4ce5923SAnton Protopopov guard(mutex)(&map->freeze_mutex); 135*b4ce5923SAnton Protopopov 136*b4ce5923SAnton Protopopov return map->frozen; 137*b4ce5923SAnton Protopopov } 138*b4ce5923SAnton Protopopov 139*b4ce5923SAnton Protopopov static bool is_insn_array(const struct bpf_map *map) 140*b4ce5923SAnton Protopopov { 141*b4ce5923SAnton Protopopov return map->map_type == BPF_MAP_TYPE_INSN_ARRAY; 142*b4ce5923SAnton Protopopov } 143*b4ce5923SAnton Protopopov 144*b4ce5923SAnton Protopopov static inline bool valid_offsets(const struct bpf_insn_array *insn_array, 145*b4ce5923SAnton Protopopov const struct bpf_prog *prog) 146*b4ce5923SAnton Protopopov { 147*b4ce5923SAnton Protopopov u32 off; 148*b4ce5923SAnton Protopopov int i; 149*b4ce5923SAnton Protopopov 150*b4ce5923SAnton Protopopov for (i = 0; i < insn_array->map.max_entries; i++) { 151*b4ce5923SAnton Protopopov off = insn_array->values[i].orig_off; 152*b4ce5923SAnton Protopopov 153*b4ce5923SAnton Protopopov if (off >= prog->len) 154*b4ce5923SAnton Protopopov return false; 155*b4ce5923SAnton Protopopov 156*b4ce5923SAnton Protopopov if (off > 0) { 157*b4ce5923SAnton Protopopov if (prog->insnsi[off-1].code == (BPF_LD | BPF_DW | BPF_IMM)) 158*b4ce5923SAnton Protopopov return false; 159*b4ce5923SAnton Protopopov } 160*b4ce5923SAnton Protopopov } 161*b4ce5923SAnton Protopopov 162*b4ce5923SAnton Protopopov return true; 163*b4ce5923SAnton Protopopov } 164*b4ce5923SAnton Protopopov 165*b4ce5923SAnton Protopopov int bpf_insn_array_init(struct bpf_map *map, const struct bpf_prog *prog) 166*b4ce5923SAnton Protopopov { 167*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 168*b4ce5923SAnton Protopopov struct bpf_insn_array_value *values = insn_array->values; 169*b4ce5923SAnton Protopopov int i; 170*b4ce5923SAnton Protopopov 171*b4ce5923SAnton Protopopov if (!is_frozen(map)) 172*b4ce5923SAnton Protopopov return -EINVAL; 173*b4ce5923SAnton Protopopov 174*b4ce5923SAnton Protopopov if (!valid_offsets(insn_array, prog)) 175*b4ce5923SAnton Protopopov return -EINVAL; 176*b4ce5923SAnton Protopopov 177*b4ce5923SAnton Protopopov /* 178*b4ce5923SAnton Protopopov * There can be only one program using the map 179*b4ce5923SAnton Protopopov */ 180*b4ce5923SAnton Protopopov if (atomic_xchg(&insn_array->used, 1)) 181*b4ce5923SAnton Protopopov return -EBUSY; 182*b4ce5923SAnton Protopopov 183*b4ce5923SAnton Protopopov /* 184*b4ce5923SAnton Protopopov * Reset all the map indexes to the original values. This is needed, 185*b4ce5923SAnton Protopopov * e.g., when a replay of verification with different log level should 186*b4ce5923SAnton Protopopov * be performed. 187*b4ce5923SAnton Protopopov */ 188*b4ce5923SAnton Protopopov for (i = 0; i < map->max_entries; i++) 189*b4ce5923SAnton Protopopov values[i].xlated_off = values[i].orig_off; 190*b4ce5923SAnton Protopopov 191*b4ce5923SAnton Protopopov return 0; 192*b4ce5923SAnton Protopopov } 193*b4ce5923SAnton Protopopov 194*b4ce5923SAnton Protopopov int bpf_insn_array_ready(struct bpf_map *map) 195*b4ce5923SAnton Protopopov { 196*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 197*b4ce5923SAnton Protopopov int i; 198*b4ce5923SAnton Protopopov 199*b4ce5923SAnton Protopopov for (i = 0; i < map->max_entries; i++) { 200*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off == INSN_DELETED) 201*b4ce5923SAnton Protopopov continue; 202*b4ce5923SAnton Protopopov if (!insn_array->ips[i]) 203*b4ce5923SAnton Protopopov return -EFAULT; 204*b4ce5923SAnton Protopopov } 205*b4ce5923SAnton Protopopov 206*b4ce5923SAnton Protopopov return 0; 207*b4ce5923SAnton Protopopov } 208*b4ce5923SAnton Protopopov 209*b4ce5923SAnton Protopopov void bpf_insn_array_release(struct bpf_map *map) 210*b4ce5923SAnton Protopopov { 211*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 212*b4ce5923SAnton Protopopov 213*b4ce5923SAnton Protopopov atomic_set(&insn_array->used, 0); 214*b4ce5923SAnton Protopopov } 215*b4ce5923SAnton Protopopov 216*b4ce5923SAnton Protopopov void bpf_insn_array_adjust(struct bpf_map *map, u32 off, u32 len) 217*b4ce5923SAnton Protopopov { 218*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 219*b4ce5923SAnton Protopopov int i; 220*b4ce5923SAnton Protopopov 221*b4ce5923SAnton Protopopov if (len <= 1) 222*b4ce5923SAnton Protopopov return; 223*b4ce5923SAnton Protopopov 224*b4ce5923SAnton Protopopov for (i = 0; i < map->max_entries; i++) { 225*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off <= off) 226*b4ce5923SAnton Protopopov continue; 227*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off == INSN_DELETED) 228*b4ce5923SAnton Protopopov continue; 229*b4ce5923SAnton Protopopov insn_array->values[i].xlated_off += len - 1; 230*b4ce5923SAnton Protopopov } 231*b4ce5923SAnton Protopopov } 232*b4ce5923SAnton Protopopov 233*b4ce5923SAnton Protopopov void bpf_insn_array_adjust_after_remove(struct bpf_map *map, u32 off, u32 len) 234*b4ce5923SAnton Protopopov { 235*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array = cast_insn_array(map); 236*b4ce5923SAnton Protopopov int i; 237*b4ce5923SAnton Protopopov 238*b4ce5923SAnton Protopopov for (i = 0; i < map->max_entries; i++) { 239*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off < off) 240*b4ce5923SAnton Protopopov continue; 241*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off == INSN_DELETED) 242*b4ce5923SAnton Protopopov continue; 243*b4ce5923SAnton Protopopov if (insn_array->values[i].xlated_off < off + len) 244*b4ce5923SAnton Protopopov insn_array->values[i].xlated_off = INSN_DELETED; 245*b4ce5923SAnton Protopopov else 246*b4ce5923SAnton Protopopov insn_array->values[i].xlated_off -= len; 247*b4ce5923SAnton Protopopov } 248*b4ce5923SAnton Protopopov } 249*b4ce5923SAnton Protopopov 250*b4ce5923SAnton Protopopov /* 251*b4ce5923SAnton Protopopov * This function is called by JITs. The image is the real program 252*b4ce5923SAnton Protopopov * image, the offsets array set up the xlated -> jitted mapping. 253*b4ce5923SAnton Protopopov * The offsets[xlated] offset should point to the beginning of 254*b4ce5923SAnton Protopopov * the jitted instruction. 255*b4ce5923SAnton Protopopov */ 256*b4ce5923SAnton Protopopov void bpf_prog_update_insn_ptrs(struct bpf_prog *prog, u32 *offsets, void *image) 257*b4ce5923SAnton Protopopov { 258*b4ce5923SAnton Protopopov struct bpf_insn_array *insn_array; 259*b4ce5923SAnton Protopopov struct bpf_map *map; 260*b4ce5923SAnton Protopopov u32 xlated_off; 261*b4ce5923SAnton Protopopov int i, j; 262*b4ce5923SAnton Protopopov 263*b4ce5923SAnton Protopopov if (!offsets || !image) 264*b4ce5923SAnton Protopopov return; 265*b4ce5923SAnton Protopopov 266*b4ce5923SAnton Protopopov for (i = 0; i < prog->aux->used_map_cnt; i++) { 267*b4ce5923SAnton Protopopov map = prog->aux->used_maps[i]; 268*b4ce5923SAnton Protopopov if (!is_insn_array(map)) 269*b4ce5923SAnton Protopopov continue; 270*b4ce5923SAnton Protopopov 271*b4ce5923SAnton Protopopov insn_array = cast_insn_array(map); 272*b4ce5923SAnton Protopopov for (j = 0; j < map->max_entries; j++) { 273*b4ce5923SAnton Protopopov xlated_off = insn_array->values[j].xlated_off; 274*b4ce5923SAnton Protopopov if (xlated_off == INSN_DELETED) 275*b4ce5923SAnton Protopopov continue; 276*b4ce5923SAnton Protopopov if (xlated_off < prog->aux->subprog_start) 277*b4ce5923SAnton Protopopov continue; 278*b4ce5923SAnton Protopopov xlated_off -= prog->aux->subprog_start; 279*b4ce5923SAnton Protopopov if (xlated_off >= prog->len) 280*b4ce5923SAnton Protopopov continue; 281*b4ce5923SAnton Protopopov 282*b4ce5923SAnton Protopopov insn_array->values[j].jitted_off = offsets[xlated_off]; 283*b4ce5923SAnton Protopopov insn_array->ips[j] = (long)(image + offsets[xlated_off]); 284*b4ce5923SAnton Protopopov } 285*b4ce5923SAnton Protopopov } 286*b4ce5923SAnton Protopopov } 287