diff options
Diffstat (limited to 'kernel')
-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 |
4 files changed, 128 insertions, 0 deletions
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 */ |