197 lines
4.6 KiB
C
197 lines
4.6 KiB
C
/* eBPF example program:
|
|
*
|
|
* - Creates arraymap in kernel with 4 bytes keys and 8 byte values
|
|
*
|
|
* - Loads eBPF program
|
|
*
|
|
* The eBPF program accesses the map passed in to store two pieces of
|
|
* information. The number of invocations of the program, which maps
|
|
* to the number of packets received, is stored to key 0. Key 1 is
|
|
* incremented on each iteration by the number of bytes stored in
|
|
* the skb.
|
|
*
|
|
* - Attaches the new program to a cgroup using BPF_PROG_ATTACH
|
|
*
|
|
* - Every second, reads map[0] and map[1] to see how many bytes and
|
|
* packets were seen on any socket of tasks in the given cgroup.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
|
|
#include <linux/bpf.h>
|
|
|
|
#include "libbpf.h"
|
|
#include "cgroup_helpers.h"
|
|
|
|
#define FOO "/foo"
|
|
#define BAR "/foo/bar/"
|
|
#define PING_CMD "ping -c1 -w1 127.0.0.1"
|
|
|
|
char bpf_log_buf[BPF_LOG_BUF_SIZE];
|
|
|
|
static int prog_load(int verdict)
|
|
{
|
|
int ret;
|
|
struct bpf_insn prog[] = {
|
|
BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
|
|
BPF_EXIT_INSN(),
|
|
};
|
|
size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
|
|
|
|
ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
|
|
prog, insns_cnt, "GPL", 0,
|
|
bpf_log_buf, BPF_LOG_BUF_SIZE);
|
|
|
|
if (ret < 0) {
|
|
log_err("Loading program");
|
|
printf("Output from verifier:\n%s\n-------\n", bpf_log_buf);
|
|
return 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int drop_prog, allow_prog, foo = 0, bar = 0, rc = 0;
|
|
|
|
allow_prog = prog_load(1);
|
|
if (!allow_prog)
|
|
goto err;
|
|
|
|
drop_prog = prog_load(0);
|
|
if (!drop_prog)
|
|
goto err;
|
|
|
|
if (setup_cgroup_environment())
|
|
goto err;
|
|
|
|
/* Create cgroup /foo, get fd, and join it */
|
|
foo = create_and_get_cgroup(FOO);
|
|
if (!foo)
|
|
goto err;
|
|
|
|
if (join_cgroup(FOO))
|
|
goto err;
|
|
|
|
if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
log_err("Attaching prog to /foo");
|
|
goto err;
|
|
}
|
|
|
|
printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
|
|
assert(system(PING_CMD) != 0);
|
|
|
|
/* Create cgroup /foo/bar, get fd, and join it */
|
|
bar = create_and_get_cgroup(BAR);
|
|
if (!bar)
|
|
goto err;
|
|
|
|
if (join_cgroup(BAR))
|
|
goto err;
|
|
|
|
printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
|
|
assert(system(PING_CMD) != 0);
|
|
|
|
if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
log_err("Attaching prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
|
|
assert(system(PING_CMD) == 0);
|
|
|
|
if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
|
|
log_err("Detaching program from /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
|
|
"This ping in cgroup /foo/bar should fail...\n");
|
|
assert(system(PING_CMD) != 0);
|
|
|
|
if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
log_err("Attaching prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
|
|
log_err("Detaching program from /foo");
|
|
goto err;
|
|
}
|
|
|
|
printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
|
|
"This ping in cgroup /foo/bar should pass...\n");
|
|
assert(system(PING_CMD) == 0);
|
|
|
|
if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
log_err("Attaching prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
|
|
errno = 0;
|
|
log_err("Unexpected success attaching prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
|
|
log_err("Detaching program from /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (!bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
|
|
errno = 0;
|
|
log_err("Unexpected success in double detach from /foo");
|
|
goto err;
|
|
}
|
|
|
|
if (bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
|
|
log_err("Attaching non-overridable prog to /foo");
|
|
goto err;
|
|
}
|
|
|
|
if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
|
|
errno = 0;
|
|
log_err("Unexpected success attaching non-overridable prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
errno = 0;
|
|
log_err("Unexpected success attaching overridable prog to /foo/bar");
|
|
goto err;
|
|
}
|
|
|
|
if (!bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 1)) {
|
|
errno = 0;
|
|
log_err("Unexpected success attaching overridable prog to /foo");
|
|
goto err;
|
|
}
|
|
|
|
if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
|
|
log_err("Attaching different non-overridable prog to /foo");
|
|
goto err;
|
|
}
|
|
|
|
goto out;
|
|
|
|
err:
|
|
rc = 1;
|
|
|
|
out:
|
|
close(foo);
|
|
close(bar);
|
|
cleanup_cgroup_environment();
|
|
if (!rc)
|
|
printf("PASS\n");
|
|
else
|
|
printf("FAIL\n");
|
|
return rc;
|
|
}
|