aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2017-10-03 01:50:22 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-04 19:05:05 -0400
commit468e2f64d220fe2dc11caa2bcb9b3a1e50fc7321 (patch)
treeda21e580b4a534f6feab72ba479b6d3e0ad951f1
parent324bda9e6c5add86ba2e1066476481c48132aca0 (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.h4
-rw-r--r--include/linux/bpf.h3
-rw-r--r--include/uapi/linux/bpf.h13
-rw-r--r--kernel/bpf/cgroup.c46
-rw-r--r--kernel/bpf/core.c38
-rw-r--r--kernel/bpf/syscall.c34
-rw-r--r--kernel/cgroup/cgroup.c10
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);
45int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, 45int __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);
47int __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 */
49int cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog, 51int 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);
51int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, 53int 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);
55int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
56 union bpf_attr __user *uattr);
53 57
54int __cgroup_bpf_run_filter_skb(struct sock *sk, 58int __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
261struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); 261struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags);
262void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); 262void bpf_prog_array_free(struct bpf_prog_array __rcu *progs);
263int bpf_prog_array_length(struct bpf_prog_array __rcu *progs);
264int 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
97enum bpf_map_type { 98enum 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
216union bpf_attr { 220union 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. */
388int __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
1415int 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
1428int 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
1415static void bpf_prog_free_deferred(struct work_struct *work) 1453static 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
1277static 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}
5764int 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 */