diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
| -rw-r--r-- | kernel/bpf/syscall.c | 88 | 
1 files changed, 73 insertions, 15 deletions
| diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4e50c0bfdb7d..50f96ea4452a 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -199,7 +199,8 @@ static int bpf_map_update_value(struct bpf_map *map, struct fd f, void *key,  		err = bpf_fd_reuseport_array_update_elem(map, key, value,  							 flags);  	} else if (map->map_type == BPF_MAP_TYPE_QUEUE || -		   map->map_type == BPF_MAP_TYPE_STACK) { +		   map->map_type == BPF_MAP_TYPE_STACK || +		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {  		err = map->ops->map_push_elem(map, value, flags);  	} else {  		rcu_read_lock(); @@ -238,7 +239,8 @@ static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,  	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {  		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);  	} else if (map->map_type == BPF_MAP_TYPE_QUEUE || -		   map->map_type == BPF_MAP_TYPE_STACK) { +		   map->map_type == BPF_MAP_TYPE_STACK || +		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {  		err = map->ops->map_peek_elem(map, value);  	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {  		/* struct_ops map requires directly updating "value" */ @@ -348,6 +350,7 @@ void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)  	map->max_entries = attr->max_entries;  	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);  	map->numa_node = bpf_map_attr_numa_node(attr); +	map->map_extra = attr->map_extra;  }  static int bpf_map_alloc_id(struct bpf_map *map) @@ -543,8 +546,10 @@ static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)  	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {  		array = container_of(map, struct bpf_array, map); -		type  = array->aux->type; -		jited = array->aux->jited; +		spin_lock(&array->aux->owner.lock); +		type  = array->aux->owner.type; +		jited = array->aux->owner.jited; +		spin_unlock(&array->aux->owner.lock);  	}  	seq_printf(m, @@ -553,6 +558,7 @@ static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)  		   "value_size:\t%u\n"  		   "max_entries:\t%u\n"  		   "map_flags:\t%#x\n" +		   "map_extra:\t%#llx\n"  		   "memlock:\t%lu\n"  		   "map_id:\t%u\n"  		   "frozen:\t%u\n", @@ -561,6 +567,7 @@ static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)  		   map->value_size,  		   map->max_entries,  		   map->map_flags, +		   (unsigned long long)map->map_extra,  		   bpf_map_memory_footprint(map),  		   map->id,  		   READ_ONCE(map->frozen)); @@ -810,7 +817,7 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,  	return ret;  } -#define BPF_MAP_CREATE_LAST_FIELD btf_vmlinux_value_type_id +#define BPF_MAP_CREATE_LAST_FIELD map_extra  /* called via syscall */  static int map_create(union bpf_attr *attr)  { @@ -831,6 +838,10 @@ static int map_create(union bpf_attr *attr)  		return -EINVAL;  	} +	if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER && +	    attr->map_extra != 0) +		return -EINVAL; +  	f_flags = bpf_get_file_flag(attr->map_flags);  	if (f_flags < 0)  		return f_flags; @@ -1080,6 +1091,14 @@ static int map_lookup_elem(union bpf_attr *attr)  	if (!value)  		goto free_key; +	if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) { +		if (copy_from_user(value, uvalue, value_size)) +			err = -EFAULT; +		else +			err = bpf_map_copy_value(map, key, value, attr->flags); +		goto free_value; +	} +  	err = bpf_map_copy_value(map, key, value, attr->flags);  	if (err)  		goto free_value; @@ -1337,12 +1356,11 @@ int generic_map_update_batch(struct bpf_map *map,  	void __user *values = u64_to_user_ptr(attr->batch.values);  	void __user *keys = u64_to_user_ptr(attr->batch.keys);  	u32 value_size, cp, max_count; -	int ufd = attr->map_fd; +	int ufd = attr->batch.map_fd;  	void *key, *value;  	struct fd f;  	int err = 0; -	f = fdget(ufd);  	if (attr->batch.elem_flags & ~BPF_F_LOCK)  		return -EINVAL; @@ -1367,6 +1385,7 @@ int generic_map_update_batch(struct bpf_map *map,  		return -ENOMEM;  	} +	f = fdget(ufd); /* bpf_map_do_batch() guarantees ufd is valid */  	for (cp = 0; cp < max_count; cp++) {  		err = -EFAULT;  		if (copy_from_user(key, keys + cp * map->key_size, @@ -1386,6 +1405,7 @@ int generic_map_update_batch(struct bpf_map *map,  	kvfree(value);  	kvfree(key); +	fdput(f);  	return err;  } @@ -1804,8 +1824,14 @@ static int bpf_prog_release(struct inode *inode, struct file *filp)  	return 0;  } +struct bpf_prog_kstats { +	u64 nsecs; +	u64 cnt; +	u64 misses; +}; +  static void bpf_prog_get_stats(const struct bpf_prog *prog, -			       struct bpf_prog_stats *stats) +			       struct bpf_prog_kstats *stats)  {  	u64 nsecs = 0, cnt = 0, misses = 0;  	int cpu; @@ -1818,9 +1844,9 @@ static void bpf_prog_get_stats(const struct bpf_prog *prog,  		st = per_cpu_ptr(prog->stats, cpu);  		do {  			start = u64_stats_fetch_begin_irq(&st->syncp); -			tnsecs = st->nsecs; -			tcnt = st->cnt; -			tmisses = st->misses; +			tnsecs = u64_stats_read(&st->nsecs); +			tcnt = u64_stats_read(&st->cnt); +			tmisses = u64_stats_read(&st->misses);  		} while (u64_stats_fetch_retry_irq(&st->syncp, start));  		nsecs += tnsecs;  		cnt += tcnt; @@ -1836,7 +1862,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)  {  	const struct bpf_prog *prog = filp->private_data;  	char prog_tag[sizeof(prog->tag) * 2 + 1] = { }; -	struct bpf_prog_stats stats; +	struct bpf_prog_kstats stats;  	bpf_prog_get_stats(prog, &stats);  	bin2hex(prog_tag, prog->tag, sizeof(prog->tag)); @@ -1848,7 +1874,8 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)  		   "prog_id:\t%u\n"  		   "run_time_ns:\t%llu\n"  		   "run_cnt:\t%llu\n" -		   "recursion_misses:\t%llu\n", +		   "recursion_misses:\t%llu\n" +		   "verified_insns:\t%u\n",  		   prog->type,  		   prog->jited,  		   prog_tag, @@ -1856,7 +1883,8 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)  		   prog->aux->id,  		   stats.nsecs,  		   stats.cnt, -		   stats.misses); +		   stats.misses, +		   prog->aux->verified_insns);  }  #endif @@ -3575,7 +3603,7 @@ static int bpf_prog_get_info_by_fd(struct file *file,  	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);  	struct bpf_prog_info info;  	u32 info_len = attr->info.info_len; -	struct bpf_prog_stats stats; +	struct bpf_prog_kstats stats;  	char __user *uinsns;  	u32 ulen;  	int err; @@ -3625,6 +3653,8 @@ static int bpf_prog_get_info_by_fd(struct file *file,  	info.run_cnt = stats.cnt;  	info.recursion_misses = stats.misses; +	info.verified_insns = prog->aux->verified_insns; +  	if (!bpf_capable()) {  		info.jited_prog_len = 0;  		info.xlated_prog_len = 0; @@ -3871,6 +3901,7 @@ static int bpf_map_get_info_by_fd(struct file *file,  	info.value_size = map->value_size;  	info.max_entries = map->max_entries;  	info.map_flags = map->map_flags; +	info.map_extra = map->map_extra;  	memcpy(info.name, map->name, sizeof(map->name));  	if (map->btf) { @@ -4753,6 +4784,31 @@ static const struct bpf_func_proto bpf_sys_close_proto = {  	.arg1_type	= ARG_ANYTHING,  }; +BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res) +{ +	if (flags) +		return -EINVAL; + +	if (name_sz <= 1 || name[name_sz - 1]) +		return -EINVAL; + +	if (!bpf_dump_raw_ok(current_cred())) +		return -EPERM; + +	*res = kallsyms_lookup_name(name); +	return *res ? 0 : -ENOENT; +} + +const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { +	.func		= bpf_kallsyms_lookup_name, +	.gpl_only	= false, +	.ret_type	= RET_INTEGER, +	.arg1_type	= ARG_PTR_TO_MEM, +	.arg2_type	= ARG_CONST_SIZE, +	.arg3_type	= ARG_ANYTHING, +	.arg4_type	= ARG_PTR_TO_LONG, +}; +  static const struct bpf_func_proto *  syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)  { @@ -4763,6 +4819,8 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)  		return &bpf_btf_find_by_name_kind_proto;  	case BPF_FUNC_sys_close:  		return &bpf_sys_close_proto; +	case BPF_FUNC_kallsyms_lookup_name: +		return &bpf_kallsyms_lookup_name_proto;  	default:  		return tracing_prog_func_proto(func_id, prog);  	} |