1239 lines · 32.3 KB · C
RawDownload
	u32 index; 	if (info->index >= map->max_entries)		return NULL; 	if (*pos == 0)		++*pos;	array = container_of(map, struct bpf_array, map);	index = info->index & array->index_mask;	if (info->percpu_value_buf)	       return array->pptrs[index];	return array->value + array->elem_size * index;} static void *bpf_array_map_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct bpf_iter_seq_array_map_info *info = seq->private;	struct bpf_map *map = info->map;	struct bpf_array *array;	u32 index; 	++*pos;	++info->index;	if (info->index >= map->max_entries)		return NULL; 	array = container_of(map, struct bpf_array, map);	index = info->index & array->index_mask;	if (info->percpu_value_buf)	       return array->pptrs[index];	return array->value + array->elem_size * index;} static int __bpf_array_map_seq_show(struct seq_file *seq, void *v){	struct bpf_iter_seq_array_map_info *info = seq->private;	struct bpf_iter__bpf_map_elem ctx = {};	struct bpf_map *map = info->map;	struct bpf_iter_meta meta;	struct bpf_prog *prog;	int off = 0, cpu = 0;	void __percpu **pptr;	u32 size; 	meta.seq = seq;	prog = bpf_iter_get_info(&meta, v == NULL);	if (!prog)		return 0; 	ctx.meta = &meta;	ctx.map = info->map;	if (v) {		ctx.key = &info->index; 		if (!info->percpu_value_buf) {			ctx.value = v;		} else {			pptr = v;			size = round_up(map->value_size, 8);			for_each_possible_cpu(cpu) {				bpf_long_memcpy(info->percpu_value_buf + off,						per_cpu_ptr(pptr, cpu),						size);				off += size;			}			ctx.value = info->percpu_value_buf;		}	} 	return bpf_iter_run_prog(prog, &ctx);} static int bpf_array_map_seq_show(struct seq_file *seq, void *v){	return __bpf_array_map_seq_show(seq, v);} static void bpf_array_map_seq_stop(struct seq_file *seq, void *v){	if (!v)		(void)__bpf_array_map_seq_show(seq, NULL);} static int bpf_iter_init_array_map(void *priv_data,				   struct bpf_iter_aux_info *aux){	struct bpf_iter_seq_array_map_info *seq_info = priv_data;	struct bpf_map *map = aux->map;	void *value_buf;	u32 buf_size; 	if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {		buf_size = round_up(map->value_size, 8) * num_possible_cpus();		value_buf = kmalloc(buf_size, GFP_USER | __GFP_NOWARN);		if (!value_buf)			return -ENOMEM; 		seq_info->percpu_value_buf = value_buf;	} 	seq_info->map = map;	return 0;} static void bpf_iter_fini_array_map(void *priv_data){	struct bpf_iter_seq_array_map_info *seq_info = priv_data; 	kfree(seq_info->percpu_value_buf);} static const struct seq_operations bpf_array_map_seq_ops = {	.start	= bpf_array_map_seq_start,	.next	= bpf_array_map_seq_next,	.stop	= bpf_array_map_seq_stop,	.show	= bpf_array_map_seq_show,}; static const struct bpf_iter_seq_info iter_seq_info = {	.seq_ops		= &bpf_array_map_seq_ops,	.init_seq_private	= bpf_iter_init_array_map,	.fini_seq_private	= bpf_iter_fini_array_map,	.seq_priv_size		= sizeof(struct bpf_iter_seq_array_map_info),}; static int array_map_btf_id;const struct bpf_map_ops array_map_ops = {	.map_alloc_check = array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = array_map_free,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = array_map_lookup_elem,	.map_update_elem = array_map_update_elem,	.map_delete_elem = array_map_delete_elem,	.map_gen_lookup = array_map_gen_lookup,	.map_direct_value_addr = array_map_direct_value_addr,	.map_direct_value_meta = array_map_direct_value_meta,	.map_mmap = array_map_mmap,	.map_seq_show_elem = array_map_seq_show_elem,	.map_check_btf = array_map_check_btf,	.map_lookup_batch = generic_map_lookup_batch,	.map_update_batch = generic_map_update_batch,	.map_btf_name = "bpf_array",	.map_btf_id = &array_map_btf_id,	.iter_seq_info = &iter_seq_info,}; static int percpu_array_map_btf_id;const struct bpf_map_ops percpu_array_map_ops = {	.map_alloc_check = array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = array_map_free,	.map_get_next_key = array_map_get_next_key,	.map_lookup_elem = percpu_array_map_lookup_elem,	.map_update_elem = array_map_update_elem,	.map_delete_elem = array_map_delete_elem,	.map_seq_show_elem = percpu_array_map_seq_show_elem,	.map_check_btf = array_map_check_btf,	.map_btf_name = "bpf_array",	.map_btf_id = &percpu_array_map_btf_id,	.iter_seq_info = &iter_seq_info,}; static int fd_array_map_alloc_check(union bpf_attr *attr){	/* only file descriptors can be stored in this type of map */	if (attr->value_size != sizeof(u32))		return -EINVAL;	/* Program read-only/write-only not supported for special maps yet. */	if (attr->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG))		return -EINVAL;	return array_map_alloc_check(attr);} static void fd_array_map_free(struct bpf_map *map){	struct bpf_array *array = container_of(map, struct bpf_array, map);	int i; 	/* make sure it's empty */	for (i = 0; i < array->map.max_entries; i++)		BUG_ON(array->ptrs[i] != NULL); 	bpf_map_area_free(array);} static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key){	return ERR_PTR(-EOPNOTSUPP);} /* only called from syscall */int bpf_fd_array_map_lookup_elem(struct bpf_map *map, void *key, u32 *value){	void **elem, *ptr;	int ret =  0; 	if (!map->ops->map_fd_sys_lookup_elem)		return -ENOTSUPP; 	rcu_read_lock();	elem = array_map_lookup_elem(map, key);	if (elem && (ptr = READ_ONCE(*elem)))		*value = map->ops->map_fd_sys_lookup_elem(ptr);	else		ret = -ENOENT;	rcu_read_unlock(); 	return ret;} /* only called from syscall */int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,				 void *key, void *value, u64 map_flags){	struct bpf_array *array = container_of(map, struct bpf_array, map);	void *new_ptr, *old_ptr;	u32 index = *(u32 *)key, ufd; 	if (map_flags != BPF_ANY)		return -EINVAL; 	if (index >= array->map.max_entries)		return -E2BIG; 	ufd = *(u32 *)value;	new_ptr = map->ops->map_fd_get_ptr(map, map_file, ufd);	if (IS_ERR(new_ptr))		return PTR_ERR(new_ptr); 	if (map->ops->map_poke_run) {		mutex_lock(&array->aux->poke_mutex);		old_ptr = xchg(array->ptrs + index, new_ptr);		map->ops->map_poke_run(map, index, old_ptr, new_ptr);		mutex_unlock(&array->aux->poke_mutex);	} else {		old_ptr = xchg(array->ptrs + index, new_ptr);	} 	if (old_ptr)		map->ops->map_fd_put_ptr(old_ptr);	return 0;} static int fd_array_map_delete_elem(struct bpf_map *map, void *key){	struct bpf_array *array = container_of(map, struct bpf_array, map);	void *old_ptr;	u32 index = *(u32 *)key; 	if (index >= array->map.max_entries)		return -E2BIG; 	if (map->ops->map_poke_run) {		mutex_lock(&array->aux->poke_mutex);		old_ptr = xchg(array->ptrs + index, NULL);		map->ops->map_poke_run(map, index, old_ptr, NULL);		mutex_unlock(&array->aux->poke_mutex);	} else {		old_ptr = xchg(array->ptrs + index, NULL);	} 	if (old_ptr) {		map->ops->map_fd_put_ptr(old_ptr);		return 0;	} else {		return -ENOENT;	}} static void *prog_fd_array_get_ptr(struct bpf_map *map,				   struct file *map_file, int fd){	struct bpf_array *array = container_of(map, struct bpf_array, map);	struct bpf_prog *prog = bpf_prog_get(fd); 	if (IS_ERR(prog))		return prog; 	if (!bpf_prog_array_compatible(array, prog)) {		bpf_prog_put(prog);		return ERR_PTR(-EINVAL);	} 	return prog;} static void prog_fd_array_put_ptr(void *ptr){	bpf_prog_put(ptr);} 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){	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);} 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_puts(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(sizeof(*elem), GFP_KERNEL);	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);} 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, ret; 		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->ip_stable is not			 *    active yet. The JIT will do the final fixup before			 *    setting it stable. The various poke->ip_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->ip_stable))				continue;			if (poke->reason != BPF_POKE_REASON_TAIL_CALL)				continue;			if (poke->tail_call.map != map ||			    poke->tail_call.key != key)				continue; 			ret = bpf_arch_text_poke(poke->ip, BPF_MOD_JUMP,						 old ? (u8 *)old->bpf_func +						 poke->adj_off : NULL,						 new ? (u8 *)new->bpf_func +						 poke->adj_off : 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);	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);

Lines 501–1000 of 1239. Previous lines