diff options
author | Martin KaFai Lau <kafai@fb.com> | 2017-06-05 15:15:48 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-06 15:41:23 -0400 |
commit | 34ad5580f8f9c86cb273ebea25c149613cd1667e (patch) | |
tree | 47618c705d66fc9f0b977716cd7c1389e1552bdc /kernel/bpf/syscall.c | |
parent | f3f1c054c288bb6e503005e6d73611151ed20e91 (diff) |
bpf: Add BPF_(PROG|MAP)_GET_NEXT_ID command
This patch adds BPF_PROG_GET_NEXT_ID and BPF_MAP_GET_NEXT_ID
to allow userspace to iterate all bpf_prog IDs and bpf_map IDs.
The API is trying to be consistent with the existing
BPF_MAP_GET_NEXT_KEY.
It is currently limited to CAP_SYS_ADMIN which we can
consider to lift it in followup patches.
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Alexei Starovoitov <ast@fb.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4c3075b5d840..2405feedb8c1 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -166,6 +166,7 @@ static void bpf_map_put_uref(struct bpf_map *map) | |||
166 | void bpf_map_put(struct bpf_map *map) | 166 | void bpf_map_put(struct bpf_map *map) |
167 | { | 167 | { |
168 | if (atomic_dec_and_test(&map->refcnt)) { | 168 | if (atomic_dec_and_test(&map->refcnt)) { |
169 | /* bpf_map_free_id() must be called first */ | ||
169 | bpf_map_free_id(map); | 170 | bpf_map_free_id(map); |
170 | INIT_WORK(&map->work, bpf_map_free_deferred); | 171 | INIT_WORK(&map->work, bpf_map_free_deferred); |
171 | schedule_work(&map->work); | 172 | schedule_work(&map->work); |
@@ -726,6 +727,7 @@ void bpf_prog_put(struct bpf_prog *prog) | |||
726 | { | 727 | { |
727 | if (atomic_dec_and_test(&prog->aux->refcnt)) { | 728 | if (atomic_dec_and_test(&prog->aux->refcnt)) { |
728 | trace_bpf_prog_put_rcu(prog); | 729 | trace_bpf_prog_put_rcu(prog); |
730 | /* bpf_prog_free_id() must be called first */ | ||
729 | bpf_prog_free_id(prog); | 731 | bpf_prog_free_id(prog); |
730 | bpf_prog_kallsyms_del(prog); | 732 | bpf_prog_kallsyms_del(prog); |
731 | call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); | 733 | call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); |
@@ -1069,6 +1071,34 @@ static int bpf_prog_test_run(const union bpf_attr *attr, | |||
1069 | return ret; | 1071 | return ret; |
1070 | } | 1072 | } |
1071 | 1073 | ||
1074 | #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id | ||
1075 | |||
1076 | static int bpf_obj_get_next_id(const union bpf_attr *attr, | ||
1077 | union bpf_attr __user *uattr, | ||
1078 | struct idr *idr, | ||
1079 | spinlock_t *lock) | ||
1080 | { | ||
1081 | u32 next_id = attr->start_id; | ||
1082 | int err = 0; | ||
1083 | |||
1084 | if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX) | ||
1085 | return -EINVAL; | ||
1086 | |||
1087 | if (!capable(CAP_SYS_ADMIN)) | ||
1088 | return -EPERM; | ||
1089 | |||
1090 | next_id++; | ||
1091 | spin_lock_bh(lock); | ||
1092 | if (!idr_get_next(idr, &next_id)) | ||
1093 | err = -ENOENT; | ||
1094 | spin_unlock_bh(lock); | ||
1095 | |||
1096 | if (!err) | ||
1097 | err = put_user(next_id, &uattr->next_id); | ||
1098 | |||
1099 | return err; | ||
1100 | } | ||
1101 | |||
1072 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) | 1102 | SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) |
1073 | { | 1103 | { |
1074 | union bpf_attr attr = {}; | 1104 | union bpf_attr attr = {}; |
@@ -1146,6 +1176,14 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
1146 | case BPF_PROG_TEST_RUN: | 1176 | case BPF_PROG_TEST_RUN: |
1147 | err = bpf_prog_test_run(&attr, uattr); | 1177 | err = bpf_prog_test_run(&attr, uattr); |
1148 | break; | 1178 | break; |
1179 | case BPF_PROG_GET_NEXT_ID: | ||
1180 | err = bpf_obj_get_next_id(&attr, uattr, | ||
1181 | &prog_idr, &prog_idr_lock); | ||
1182 | break; | ||
1183 | case BPF_MAP_GET_NEXT_ID: | ||
1184 | err = bpf_obj_get_next_id(&attr, uattr, | ||
1185 | &map_idr, &map_idr_lock); | ||
1186 | break; | ||
1149 | default: | 1187 | default: |
1150 | err = -EINVAL; | 1188 | err = -EINVAL; |
1151 | break; | 1189 | break; |