1460 lines · 38.9 KB · C
RawDownload
	/* bpf_prog is freed after one RCU or tasks trace grace period */	bpf_prog_put(prog);} static u32 prog_fd_array_sys_lookup_elem(void *ptr){	return ((struct bpf_prog *)ptr)->aux->id;} /* decrement refcnt of all bpf_progs that are stored in this map */static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer){	struct bpf_array *array = container_of(map, struct bpf_array, map);	int i; 	for (i = 0; i < array->map.max_entries; i++) {		__fd_array_map_delete_elem(map, &i, need_defer);		cond_resched();	}} static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key,					 struct seq_file *m){	void **elem, *ptr;	u32 prog_id; 	rcu_read_lock(); 	elem = array_map_lookup_elem(map, key);	if (elem) {		ptr = READ_ONCE(*elem);		if (ptr) {			seq_printf(m, "%u: ", *(u32 *)key);			prog_id = prog_fd_array_sys_lookup_elem(ptr);			btf_type_seq_show(map->btf, map->btf_value_type_id,					  &prog_id, m);			seq_putc(m, '\n');		}	} 	rcu_read_unlock();} struct prog_poke_elem {	struct list_head list;	struct bpf_prog_aux *aux;}; static int prog_array_map_poke_track(struct bpf_map *map,				     struct bpf_prog_aux *prog_aux){	struct prog_poke_elem *elem;	struct bpf_array_aux *aux;	int ret = 0; 	aux = container_of(map, struct bpf_array, map)->aux;	mutex_lock(&aux->poke_mutex);	list_for_each_entry(elem, &aux->poke_progs, list) {		if (elem->aux == prog_aux)			goto out;	} 	elem = kmalloc_obj(*elem);	if (!elem) {		ret = -ENOMEM;		goto out;	} 	INIT_LIST_HEAD(&elem->list);	/* We must track the program's aux info at this point in time	 * since the program pointer itself may not be stable yet, see	 * also comment in prog_array_map_poke_run().	 */	elem->aux = prog_aux; 	list_add_tail(&elem->list, &aux->poke_progs);out:	mutex_unlock(&aux->poke_mutex);	return ret;} static void prog_array_map_poke_untrack(struct bpf_map *map,					struct bpf_prog_aux *prog_aux){	struct prog_poke_elem *elem, *tmp;	struct bpf_array_aux *aux; 	aux = container_of(map, struct bpf_array, map)->aux;	mutex_lock(&aux->poke_mutex);	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {		if (elem->aux == prog_aux) {			list_del_init(&elem->list);			kfree(elem);			break;		}	}	mutex_unlock(&aux->poke_mutex);} void __weak bpf_arch_poke_desc_update(struct bpf_jit_poke_descriptor *poke,				      struct bpf_prog *new, struct bpf_prog *old){	WARN_ON_ONCE(1);} static void prog_array_map_poke_run(struct bpf_map *map, u32 key,				    struct bpf_prog *old,				    struct bpf_prog *new){	struct prog_poke_elem *elem;	struct bpf_array_aux *aux; 	aux = container_of(map, struct bpf_array, map)->aux;	WARN_ON_ONCE(!mutex_is_locked(&aux->poke_mutex)); 	list_for_each_entry(elem, &aux->poke_progs, list) {		struct bpf_jit_poke_descriptor *poke;		int i; 		for (i = 0; i < elem->aux->size_poke_tab; i++) {			poke = &elem->aux->poke_tab[i]; 			/* Few things to be aware of:			 *			 * 1) We can only ever access aux in this context, but			 *    not aux->prog since it might not be stable yet and			 *    there could be danger of use after free otherwise.			 * 2) Initially when we start tracking aux, the program			 *    is not JITed yet and also does not have a kallsyms			 *    entry. We skip these as poke->tailcall_target_stable			 *    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) 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.			 */			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; 			bpf_arch_poke_desc_update(poke, new, old);		}	}} 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, true);	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_obj(*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 = bpf_array_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_mem_usage = array_map_mem_usage,	.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_obj(*ee);	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(struct bpf_map *map, void *ptr, bool need_defer){	/* bpf_perf_event is freed after one RCU grace period */	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, true);	}	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, false);	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 = bpf_array_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_mem_usage = array_map_mem_usage,	.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(struct bpf_map *map, void *ptr, bool need_defer){	/* 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, false);	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 = bpf_array_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_mem_usage = array_map_mem_usage,	.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, false);	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 = array->elem_size;	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 = bpf_array_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_mem_usage = array_map_mem_usage,	.map_btf_id = &array_map_btf_ids[0],};

Lines 1001–1460 of 1460. Previous lines