1367 lines · 36.0 KB · C
RawDownload
			 *    is not active yet. The JIT will do the final fixup			 *    before setting it stable. The various			 *    poke->tailcall_target_stable are successively			 *    activated, so tail call updates can arrive from here			 *    while JIT is still finishing its final fixup for			 *    non-activated poke entries.			 * 3) On program teardown, the program's kallsym entry gets			 *    removed out of RCU callback, but we can only untrack			 *    from sleepable context, therefore bpf_arch_text_poke()			 *    might not see that this is in BPF text section and			 *    bails out with -EINVAL. As these are unreachable since			 *    RCU grace period already passed, we simply skip them.			 * 4) Also programs reaching refcount of zero while patching			 *    is in progress is okay since we're protected under			 *    poke_mutex and untrack the programs before the JIT			 *    buffer is freed. When we're still in the middle of			 *    patching and suddenly kallsyms entry of the program			 *    gets evicted, we just skip the rest which is fine due			 *    to point 3).			 * 5) Any other error happening below from bpf_arch_text_poke()			 *    is a unexpected bug.			 */			if (!READ_ONCE(poke->tailcall_target_stable))				continue;			if (poke->reason != BPF_POKE_REASON_TAIL_CALL)				continue;			if (poke->tail_call.map != map ||			    poke->tail_call.key != key)				continue; 			old_bypass_addr = old ? NULL : poke->bypass_addr;			old_addr = old ? (u8 *)old->bpf_func + poke->adj_off : NULL;			new_addr = new ? (u8 *)new->bpf_func + poke->adj_off : NULL; 			if (new) {				ret = bpf_arch_text_poke(poke->tailcall_target,							 BPF_MOD_JUMP,							 old_addr, new_addr);				BUG_ON(ret < 0 && ret != -EINVAL);				if (!old) {					ret = bpf_arch_text_poke(poke->tailcall_bypass,								 BPF_MOD_JUMP,								 poke->bypass_addr,								 NULL);					BUG_ON(ret < 0 && ret != -EINVAL);				}			} else {				ret = bpf_arch_text_poke(poke->tailcall_bypass,							 BPF_MOD_JUMP,							 old_bypass_addr,							 poke->bypass_addr);				BUG_ON(ret < 0 && ret != -EINVAL);				/* let other CPUs finish the execution of program				 * so that it will not possible to expose them				 * to invalid nop, stack unwind, nop state				 */				if (!ret)					synchronize_rcu();				ret = bpf_arch_text_poke(poke->tailcall_target,							 BPF_MOD_JUMP,							 old_addr, NULL);				BUG_ON(ret < 0 && ret != -EINVAL);			}		}	}} static void prog_array_map_clear_deferred(struct work_struct *work){	struct bpf_map *map = container_of(work, struct bpf_array_aux,					   work)->map;	bpf_fd_array_map_clear(map);	bpf_map_put(map);} static void prog_array_map_clear(struct bpf_map *map){	struct bpf_array_aux *aux = container_of(map, struct bpf_array,						 map)->aux;	bpf_map_inc(map);	schedule_work(&aux->work);} static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr){	struct bpf_array_aux *aux;	struct bpf_map *map; 	aux = kzalloc(sizeof(*aux), GFP_KERNEL_ACCOUNT);	if (!aux)		return ERR_PTR(-ENOMEM); 	INIT_WORK(&aux->work, prog_array_map_clear_deferred);	INIT_LIST_HEAD(&aux->poke_progs);	mutex_init(&aux->poke_mutex); 	map = array_map_alloc(attr);	if (IS_ERR(map)) {		kfree(aux);		return map;	} 	container_of(map, struct bpf_array, map)->aux = aux;	aux->map = map; 	return map;} static void prog_array_map_free(struct bpf_map *map){	struct prog_poke_elem *elem, *tmp;	struct bpf_array_aux *aux; 	aux = container_of(map, struct bpf_array, map)->aux;	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {		list_del_init(&elem->list);		kfree(elem);	}	kfree(aux);	fd_array_map_free(map);} /* prog_array->aux->{type,jited} is a runtime binding. * Doing static check alone in the verifier is not enough. * Thus, prog_array_map cannot be used as an inner_map * and map_meta_equal is not implemented. */const struct bpf_map_ops prog_array_map_ops = {	.map_alloc_check = fd_array_map_alloc_check,	.map_alloc = prog_array_map_alloc,	.map_free = prog_array_map_free,	.map_poke_track = prog_array_map_poke_track,	.map_poke_untrack = prog_array_map_poke_untrack,	.map_poke_run = prog_array_map_poke_run,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = fd_array_map_lookup_elem,	.map_delete_elem = fd_array_map_delete_elem,	.map_fd_get_ptr = prog_fd_array_get_ptr,	.map_fd_put_ptr = prog_fd_array_put_ptr,	.map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem,	.map_release_uref = prog_array_map_clear,	.map_seq_show_elem = prog_array_map_seq_show_elem,	.map_btf_id = &array_map_btf_ids[0],}; static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file,						   struct file *map_file){	struct bpf_event_entry *ee; 	ee = kzalloc(sizeof(*ee), GFP_ATOMIC);	if (ee) {		ee->event = perf_file->private_data;		ee->perf_file = perf_file;		ee->map_file = map_file;	} 	return ee;} static void __bpf_event_entry_free(struct rcu_head *rcu){	struct bpf_event_entry *ee; 	ee = container_of(rcu, struct bpf_event_entry, rcu);	fput(ee->perf_file);	kfree(ee);} static void bpf_event_entry_free_rcu(struct bpf_event_entry *ee){	call_rcu(&ee->rcu, __bpf_event_entry_free);} static void *perf_event_fd_array_get_ptr(struct bpf_map *map,					 struct file *map_file, int fd){	struct bpf_event_entry *ee;	struct perf_event *event;	struct file *perf_file;	u64 value; 	perf_file = perf_event_get(fd);	if (IS_ERR(perf_file))		return perf_file; 	ee = ERR_PTR(-EOPNOTSUPP);	event = perf_file->private_data;	if (perf_event_read_local(event, &value, NULL, NULL) == -EOPNOTSUPP)		goto err_out; 	ee = bpf_event_entry_gen(perf_file, map_file);	if (ee)		return ee;	ee = ERR_PTR(-ENOMEM);err_out:	fput(perf_file);	return ee;} static void perf_event_fd_array_put_ptr(void *ptr){	bpf_event_entry_free_rcu(ptr);} static void perf_event_fd_array_release(struct bpf_map *map,					struct file *map_file){	struct bpf_array *array = container_of(map, struct bpf_array, map);	struct bpf_event_entry *ee;	int i; 	if (map->map_flags & BPF_F_PRESERVE_ELEMS)		return; 	rcu_read_lock();	for (i = 0; i < array->map.max_entries; i++) {		ee = READ_ONCE(array->ptrs[i]);		if (ee && ee->map_file == map_file)			fd_array_map_delete_elem(map, &i);	}	rcu_read_unlock();} static void perf_event_fd_array_map_free(struct bpf_map *map){	if (map->map_flags & BPF_F_PRESERVE_ELEMS)		bpf_fd_array_map_clear(map);	fd_array_map_free(map);} const struct bpf_map_ops perf_event_array_map_ops = {	.map_meta_equal = bpf_map_meta_equal,	.map_alloc_check = fd_array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = perf_event_fd_array_map_free,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = fd_array_map_lookup_elem,	.map_delete_elem = fd_array_map_delete_elem,	.map_fd_get_ptr = perf_event_fd_array_get_ptr,	.map_fd_put_ptr = perf_event_fd_array_put_ptr,	.map_release = perf_event_fd_array_release,	.map_check_btf = map_check_no_btf,	.map_btf_id = &array_map_btf_ids[0],}; #ifdef CONFIG_CGROUPSstatic void *cgroup_fd_array_get_ptr(struct bpf_map *map,				     struct file *map_file /* not used */,				     int fd){	return cgroup_get_from_fd(fd);} static void cgroup_fd_array_put_ptr(void *ptr){	/* cgroup_put free cgrp after a rcu grace period */	cgroup_put(ptr);} static void cgroup_fd_array_free(struct bpf_map *map){	bpf_fd_array_map_clear(map);	fd_array_map_free(map);} const struct bpf_map_ops cgroup_array_map_ops = {	.map_meta_equal = bpf_map_meta_equal,	.map_alloc_check = fd_array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = cgroup_fd_array_free,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = fd_array_map_lookup_elem,	.map_delete_elem = fd_array_map_delete_elem,	.map_fd_get_ptr = cgroup_fd_array_get_ptr,	.map_fd_put_ptr = cgroup_fd_array_put_ptr,	.map_check_btf = map_check_no_btf,	.map_btf_id = &array_map_btf_ids[0],};#endif static struct bpf_map *array_of_map_alloc(union bpf_attr *attr){	struct bpf_map *map, *inner_map_meta; 	inner_map_meta = bpf_map_meta_alloc(attr->inner_map_fd);	if (IS_ERR(inner_map_meta))		return inner_map_meta; 	map = array_map_alloc(attr);	if (IS_ERR(map)) {		bpf_map_meta_free(inner_map_meta);		return map;	} 	map->inner_map_meta = inner_map_meta; 	return map;} static void array_of_map_free(struct bpf_map *map){	/* map->inner_map_meta is only accessed by syscall which	 * is protected by fdget/fdput.	 */	bpf_map_meta_free(map->inner_map_meta);	bpf_fd_array_map_clear(map);	fd_array_map_free(map);} static void *array_of_map_lookup_elem(struct bpf_map *map, void *key){	struct bpf_map **inner_map = array_map_lookup_elem(map, key); 	if (!inner_map)		return NULL; 	return READ_ONCE(*inner_map);} static int array_of_map_gen_lookup(struct bpf_map *map,				   struct bpf_insn *insn_buf){	struct bpf_array *array = container_of(map, struct bpf_array, map);	u32 elem_size = round_up(map->value_size, 8);	struct bpf_insn *insn = insn_buf;	const int ret = BPF_REG_0;	const int map_ptr = BPF_REG_1;	const int index = BPF_REG_2; 	*insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));	*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0);	if (!map->bypass_spec_v1) {		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 6);		*insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask);	} else {		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5);	}	if (is_power_of_2(elem_size))		*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size));	else		*insn++ = BPF_ALU64_IMM(BPF_MUL, ret, elem_size);	*insn++ = BPF_ALU64_REG(BPF_ADD, ret, map_ptr);	*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0);	*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 1);	*insn++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);	*insn++ = BPF_MOV64_IMM(ret, 0); 	return insn - insn_buf;} const struct bpf_map_ops array_of_maps_map_ops = {	.map_alloc_check = fd_array_map_alloc_check,	.map_alloc = array_of_map_alloc,	.map_free = array_of_map_free,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = array_of_map_lookup_elem,	.map_delete_elem = fd_array_map_delete_elem,	.map_fd_get_ptr = bpf_map_fd_get_ptr,	.map_fd_put_ptr = bpf_map_fd_put_ptr,	.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem,	.map_gen_lookup = array_of_map_gen_lookup,	.map_lookup_batch = generic_map_lookup_batch,	.map_update_batch = generic_map_update_batch,	.map_check_btf = map_check_no_btf,	.map_btf_id = &array_map_btf_ids[0],};

Lines 1001–1367 of 1367. Previous lines