diff options
author | Alexei Starovoitov <ast@fb.com> | 2017-10-03 01:50:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-04 19:05:05 -0400 |
commit | 468e2f64d220fe2dc11caa2bcb9b3a1e50fc7321 (patch) | |
tree | da21e580b4a534f6feab72ba479b6d3e0ad951f1 | |
parent | 324bda9e6c5add86ba2e1066476481c48132aca0 (diff) |
bpf: introduce BPF_PROG_QUERY command
introduce BPF_PROG_QUERY command to retrieve a set of either
attached programs to given cgroup or a set of effective programs
that will execute for events within a cgroup
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
for cgroup bits
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/bpf-cgroup.h | 4 | ||||
-rw-r--r-- | include/linux/bpf.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/bpf.h | 13 | ||||
-rw-r--r-- | kernel/bpf/cgroup.c | 46 | ||||
-rw-r--r-- | kernel/bpf/core.c | 38 | ||||
-rw-r--r-- | kernel/bpf/syscall.c | 34 | ||||
-rw-r--r-- | kernel/cgroup/cgroup.c | 10 |
7 files changed, 148 insertions, 0 deletions
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h index 102e56fbb6de..359b6f5d3d90 100644 --- a/include/linux/bpf-cgroup.h +++ b/include/linux/bpf-cgroup.h | |||
@@ -44,12 +44,16 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, | |||
44 | enum bpf_attach_type type, u32 flags); | 44 | enum bpf_attach_type type, u32 flags); |
45 | int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, | 45 | int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, |
46 | enum bpf_attach_type type, u32 flags); | 46 | enum bpf_attach_type type, u32 flags); |
47 | int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, | ||
48 | union bpf_attr __user *uattr); | ||
47 | 49 | ||
48 | /* Wrapper for __cgroup_bpf_*() protected by cgroup_mutex */ | 50 | /* Wrapper for __cgroup_bpf_*() protected by cgroup_mutex */ |
49 | int cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, | 51 | int cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, |
50 | enum bpf_attach_type type, u32 flags); | 52 | enum bpf_attach_type type, u32 flags); |
51 | int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, | 53 | int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, |
52 | enum bpf_attach_type type, u32 flags); | 54 | enum bpf_attach_type type, u32 flags); |
55 | int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, | ||
56 | union bpf_attr __user *uattr); | ||
53 | 57 | ||
54 | int __cgroup_bpf_run_filter_skb(struct sock *sk, | 58 | int __cgroup_bpf_run_filter_skb(struct sock *sk, |
55 | struct sk_buff *skb, | 59 | struct sk_buff *skb, |
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a6964b75f070..a67daea731ab 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
@@ -260,6 +260,9 @@ struct bpf_prog_array { | |||
260 | 260 | ||
261 | struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); | 261 | struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); |
262 | void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); | 262 | void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); |
263 | int bpf_prog_array_length(struct bpf_prog_array __rcu *progs); | ||
264 | int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, | ||
265 | __u32 __user *prog_ids, u32 cnt); | ||
263 | 266 | ||
264 | #define BPF_PROG_RUN_ARRAY(array, ctx, func) \ | 267 | #define BPF_PROG_RUN_ARRAY(array, ctx, func) \ |
265 | ({ \ | 268 | ({ \ |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 762f74bc6c47..cb2b9f95160a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
@@ -92,6 +92,7 @@ enum bpf_cmd { | |||
92 | BPF_PROG_GET_FD_BY_ID, | 92 | BPF_PROG_GET_FD_BY_ID, |
93 | BPF_MAP_GET_FD_BY_ID, | 93 | BPF_MAP_GET_FD_BY_ID, |
94 | BPF_OBJ_GET_INFO_BY_FD, | 94 | BPF_OBJ_GET_INFO_BY_FD, |
95 | BPF_PROG_QUERY, | ||
95 | }; | 96 | }; |
96 | 97 | ||
97 | enum bpf_map_type { | 98 | enum bpf_map_type { |
@@ -211,6 +212,9 @@ enum bpf_attach_type { | |||
211 | /* Specify numa node during map creation */ | 212 | /* Specify numa node during map creation */ |
212 | #define BPF_F_NUMA_NODE (1U << 2) | 213 | #define BPF_F_NUMA_NODE (1U << 2) |
213 | 214 | ||
215 | /* flags for BPF_PROG_QUERY */ | ||
216 | #define BPF_F_QUERY_EFFECTIVE (1U << 0) | ||
217 | |||
214 | #define BPF_OBJ_NAME_LEN 16U | 218 | #define BPF_OBJ_NAME_LEN 16U |
215 | 219 | ||
216 | union bpf_attr { | 220 | union bpf_attr { |
@@ -289,6 +293,15 @@ union bpf_attr { | |||
289 | __u32 info_len; | 293 | __u32 info_len; |
290 | __aligned_u64 info; | 294 | __aligned_u64 info; |
291 | } info; | 295 | } info; |
296 | |||
297 | struct { /* anonymous struct used by BPF_PROG_QUERY command */ | ||
298 | __u32 target_fd; /* container object to query */ | ||
299 | __u32 attach_type; | ||
300 | __u32 query_flags; | ||
301 | __u32 attach_flags; | ||
302 | __aligned_u64 prog_ids; | ||
303 | __u32 prog_cnt; | ||
304 | } query; | ||
292 | } __attribute__((aligned(8))); | 305 | } __attribute__((aligned(8))); |
293 | 306 | ||
294 | /* BPF helper function descriptions: | 307 | /* BPF helper function descriptions: |
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 6b7500bbdb53..e88abc0865d5 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c | |||
@@ -384,6 +384,52 @@ cleanup: | |||
384 | return err; | 384 | return err; |
385 | } | 385 | } |
386 | 386 | ||
387 | /* Must be called with cgroup_mutex held to avoid races. */ | ||
388 | int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, | ||
389 | union bpf_attr __user *uattr) | ||
390 | { | ||
391 | __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); | ||
392 | enum bpf_attach_type type = attr->query.attach_type; | ||
393 | struct list_head *progs = &cgrp->bpf.progs[type]; | ||
394 | u32 flags = cgrp->bpf.flags[type]; | ||
395 | int cnt, ret = 0, i; | ||
396 | |||
397 | if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE) | ||
398 | cnt = bpf_prog_array_length(cgrp->bpf.effective[type]); | ||
399 | else | ||
400 | cnt = prog_list_length(progs); | ||
401 | |||
402 | if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) | ||
403 | return -EFAULT; | ||
404 | if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt))) | ||
405 | return -EFAULT; | ||
406 | if (attr->query.prog_cnt == 0 || !prog_ids || !cnt) | ||
407 | /* return early if user requested only program count + flags */ | ||
408 | return 0; | ||
409 | if (attr->query.prog_cnt < cnt) { | ||
410 | cnt = attr->query.prog_cnt; | ||
411 | ret = -ENOSPC; | ||
412 | } | ||
413 | |||
414 | if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE) { | ||
415 | return bpf_prog_array_copy_to_user(cgrp->bpf.effective[type], | ||
416 | prog_ids, cnt); | ||
417 | } else { | ||
418 | struct bpf_prog_list *pl; | ||
419 | u32 id; | ||
420 | |||
421 | i = 0; | ||
422 | list_for_each_entry(pl, progs, node) { | ||
423 | id = pl->prog->aux->id; | ||
424 | if (copy_to_user(prog_ids + i, &id, sizeof(id))) | ||
425 | return -EFAULT; | ||
426 | if (++i == cnt) | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | return ret; | ||
431 | } | ||
432 | |||
387 | /** | 433 | /** |
388 | * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering | 434 | * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering |
389 | * @sk: The socket sending or receiving traffic | 435 | * @sk: The socket sending or receiving traffic |
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 6b49e1991ae7..eba966c09053 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -1412,6 +1412,44 @@ void bpf_prog_array_free(struct bpf_prog_array __rcu *progs) | |||
1412 | kfree_rcu(progs, rcu); | 1412 | kfree_rcu(progs, rcu); |
1413 | } | 1413 | } |
1414 | 1414 | ||
1415 | int bpf_prog_array_length(struct bpf_prog_array __rcu *progs) | ||
1416 | { | ||
1417 | struct bpf_prog **prog; | ||
1418 | u32 cnt = 0; | ||
1419 | |||
1420 | rcu_read_lock(); | ||
1421 | prog = rcu_dereference(progs)->progs; | ||
1422 | for (; *prog; prog++) | ||
1423 | cnt++; | ||
1424 | rcu_read_unlock(); | ||
1425 | return cnt; | ||
1426 | } | ||
1427 | |||
1428 | int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, | ||
1429 | __u32 __user *prog_ids, u32 cnt) | ||
1430 | { | ||
1431 | struct bpf_prog **prog; | ||
1432 | u32 i = 0, id; | ||
1433 | |||
1434 | rcu_read_lock(); | ||
1435 | prog = rcu_dereference(progs)->progs; | ||
1436 | for (; *prog; prog++) { | ||
1437 | id = (*prog)->aux->id; | ||
1438 | if (copy_to_user(prog_ids + i, &id, sizeof(id))) { | ||
1439 | rcu_read_unlock(); | ||
1440 | return -EFAULT; | ||
1441 | } | ||
1442 | if (++i == cnt) { | ||
1443 | prog++; | ||
1444 | break; | ||
1445 | } | ||
1446 | } | ||
1447 | rcu_read_unlock(); | ||
1448 | if (*prog) | ||
1449 | return -ENOSPC; | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1415 | static void bpf_prog_free_deferred(struct work_struct *work) | 1453 | static void bpf_prog_free_deferred(struct work_struct *work) |
1416 | { | 1454 | { |
1417 | struct bpf_prog_aux *aux; | 1455 | struct bpf_prog_aux *aux; |
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 51bee695d32c..0048cb24ba7b 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -1272,6 +1272,37 @@ static int bpf_prog_detach(const union bpf_attr *attr) | |||
1272 | return ret; | 1272 | return ret; |
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | #define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt | ||
1276 | |||
1277 | static int bpf_prog_query(const union bpf_attr *attr, | ||
1278 | union bpf_attr __user *uattr) | ||
1279 | { | ||
1280 | struct cgroup *cgrp; | ||
1281 | int ret; | ||
1282 | |||
1283 | if (!capable(CAP_NET_ADMIN)) | ||
1284 | return -EPERM; | ||
1285 | if (CHECK_ATTR(BPF_PROG_QUERY)) | ||
1286 | return -EINVAL; | ||
1287 | if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | switch (attr->query.attach_type) { | ||
1291 | case BPF_CGROUP_INET_INGRESS: | ||
1292 | case BPF_CGROUP_INET_EGRESS: | ||
1293 | case BPF_CGROUP_INET_SOCK_CREATE: | ||
1294 | case BPF_CGROUP_SOCK_OPS: | ||
1295 | break; | ||
1296 | default: | ||
1297 | return -EINVAL; | ||
1298 | } | ||
1299 | cgrp = cgroup_get_from_fd(attr->query.target_fd); | ||
1300 | if (IS_ERR(cgrp)) | ||
1301 | return PTR_ERR(cgrp); | ||
1302 | ret = cgroup_bpf_query(cgrp, attr, uattr); | ||
1303 | cgroup_put(cgrp); | ||
1304 | return ret; | ||
1305 | } | ||
1275 | #endif /* CONFIG_CGROUP_BPF */ | 1306 | #endif /* CONFIG_CGROUP_BPF */ |
1276 | 1307 | ||
1277 | #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration | 1308 | #define BPF_PROG_TEST_RUN_LAST_FIELD test.duration |
@@ -1568,6 +1599,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
1568 | case BPF_PROG_DETACH: | 1599 | case BPF_PROG_DETACH: |
1569 | err = bpf_prog_detach(&attr); | 1600 | err = bpf_prog_detach(&attr); |
1570 | break; | 1601 | break; |
1602 | case BPF_PROG_QUERY: | ||
1603 | err = bpf_prog_query(&attr, uattr); | ||
1604 | break; | ||
1571 | #endif | 1605 | #endif |
1572 | case BPF_PROG_TEST_RUN: | 1606 | case BPF_PROG_TEST_RUN: |
1573 | err = bpf_prog_test_run(&attr, uattr); | 1607 | err = bpf_prog_test_run(&attr, uattr); |
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 57eb866ae78d..269512b94a94 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c | |||
@@ -5761,4 +5761,14 @@ int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, | |||
5761 | mutex_unlock(&cgroup_mutex); | 5761 | mutex_unlock(&cgroup_mutex); |
5762 | return ret; | 5762 | return ret; |
5763 | } | 5763 | } |
5764 | int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr, | ||
5765 | union bpf_attr __user *uattr) | ||
5766 | { | ||
5767 | int ret; | ||
5768 | |||
5769 | mutex_lock(&cgroup_mutex); | ||
5770 | ret = __cgroup_bpf_query(cgrp, attr, uattr); | ||
5771 | mutex_unlock(&cgroup_mutex); | ||
5772 | return ret; | ||
5773 | } | ||
5764 | #endif /* CONFIG_CGROUP_BPF */ | 5774 | #endif /* CONFIG_CGROUP_BPF */ |