diff options
author | Martin KaFai Lau <kafai@fb.com> | 2018-05-04 17:49:51 -0400 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2018-05-09 11:25:13 -0400 |
commit | 78958fca7ead2f81b60a6827881c4866d1ed0c52 (patch) | |
tree | 541a6090ce06d7bc6f708f5a70a0cd4bff187ac2 /kernel/bpf/syscall.c | |
parent | 82e9697250977f3f87cd42e71e8daa8810e64520 (diff) |
bpf: btf: Introduce BTF ID
This patch gives an ID to each loaded BTF. The ID is allocated by
the idr like the existing prog-id and map-id.
The bpf_put(map->btf) is moved to __bpf_map_put() so that the
userspace can stop seeing the BTF ID ASAP when the last BTF
refcnt is gone.
It also makes BTF accessible from userspace through the
1. new BPF_BTF_GET_FD_BY_ID command. It is limited to CAP_SYS_ADMIN
which is inline with the BPF_BTF_LOAD cmd and the existing
BPF_[MAP|PROG]_GET_FD_BY_ID cmd.
2. new btf_id (and btf_key_id + btf_value_id) in "struct bpf_map_info"
Once the BTF ID handler is accessible from userspace, freeing a BTF
object has to go through a rcu period. The BPF_BTF_GET_FD_BY_ID cmd
can then be done under a rcu_read_lock() instead of taking
spin_lock.
[Note: A similar rcu usage can be done to the existing
bpf_prog_get_fd_by_id() in a follow up patch]
When processing the BPF_BTF_GET_FD_BY_ID cmd,
refcount_inc_not_zero() is needed because the BTF object
could be already in the rcu dead row . btf_get() is
removed since its usage is currently limited to btf.c
alone. refcount_inc() is used directly instead.
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Alexei Starovoitov <ast@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 9b87198deea2..31c4092da277 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -252,7 +252,6 @@ static void bpf_map_free_deferred(struct work_struct *work) | |||
252 | 252 | ||
253 | bpf_map_uncharge_memlock(map); | 253 | bpf_map_uncharge_memlock(map); |
254 | security_bpf_map_free(map); | 254 | security_bpf_map_free(map); |
255 | btf_put(map->btf); | ||
256 | /* implementation dependent freeing */ | 255 | /* implementation dependent freeing */ |
257 | map->ops->map_free(map); | 256 | map->ops->map_free(map); |
258 | } | 257 | } |
@@ -273,6 +272,7 @@ static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) | |||
273 | if (atomic_dec_and_test(&map->refcnt)) { | 272 | if (atomic_dec_and_test(&map->refcnt)) { |
274 | /* bpf_map_free_id() must be called first */ | 273 | /* bpf_map_free_id() must be called first */ |
275 | bpf_map_free_id(map, do_idr_lock); | 274 | bpf_map_free_id(map, do_idr_lock); |
275 | btf_put(map->btf); | ||
276 | INIT_WORK(&map->work, bpf_map_free_deferred); | 276 | INIT_WORK(&map->work, bpf_map_free_deferred); |
277 | schedule_work(&map->work); | 277 | schedule_work(&map->work); |
278 | } | 278 | } |
@@ -2002,6 +2002,12 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map, | |||
2002 | info.map_flags = map->map_flags; | 2002 | info.map_flags = map->map_flags; |
2003 | memcpy(info.name, map->name, sizeof(map->name)); | 2003 | memcpy(info.name, map->name, sizeof(map->name)); |
2004 | 2004 | ||
2005 | if (map->btf) { | ||
2006 | info.btf_id = btf_id(map->btf); | ||
2007 | info.btf_key_id = map->btf_key_id; | ||
2008 | info.btf_value_id = map->btf_value_id; | ||
2009 | } | ||
2010 | |||
2005 | if (bpf_map_is_dev_bound(map)) { | 2011 | if (bpf_map_is_dev_bound(map)) { |
2006 | err = bpf_map_offload_info_fill(&info, map); | 2012 | err = bpf_map_offload_info_fill(&info, map); |
2007 | if (err) | 2013 | if (err) |
@@ -2059,6 +2065,19 @@ static int bpf_btf_load(const union bpf_attr *attr) | |||
2059 | return btf_new_fd(attr); | 2065 | return btf_new_fd(attr); |
2060 | } | 2066 | } |
2061 | 2067 | ||
2068 | #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id | ||
2069 | |||
2070 | static int bpf_btf_get_fd_by_id(const union bpf_attr *attr) | ||
2071 | { | ||
2072 | if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID)) | ||
2073 | return -EINVAL; | ||
2074 | |||
2075 | if (!capable(CAP_SYS_ADMIN)) | ||
2076 | return -EPERM; | ||
2077 | |||
2078 | return btf_get_fd_by_id(attr->btf_id); | ||
2079 | } | ||
2080 | |||
2062 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) | 2081 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) |
2063 | { | 2082 | { |
2064 | union bpf_attr attr = {}; | 2083 | union bpf_attr attr = {}; |
@@ -2142,6 +2161,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
2142 | case BPF_BTF_LOAD: | 2161 | case BPF_BTF_LOAD: |
2143 | err = bpf_btf_load(&attr); | 2162 | err = bpf_btf_load(&attr); |
2144 | break; | 2163 | break; |
2164 | case BPF_BTF_GET_FD_BY_ID: | ||
2165 | err = bpf_btf_get_fd_by_id(&attr); | ||
2166 | break; | ||
2145 | default: | 2167 | default: |
2146 | err = -EINVAL; | 2168 | err = -EINVAL; |
2147 | break; | 2169 | break; |