Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4324551 authored by Daniel Mack's avatar Daniel Mack Committed by David S. Miller
Browse files

bpf: add BPF_PROG_ATTACH and BPF_PROG_DETACH commands



Extend the bpf(2) syscall by two new commands, BPF_PROG_ATTACH and
BPF_PROG_DETACH which allow attaching and detaching eBPF programs
to a target.

On the API level, the target could be anything that has an fd in
userspace, hence the name of the field in union bpf_attr is called
'target_fd'.

When called with BPF_ATTACH_TYPE_CGROUP_INET_{E,IN}GRESS, the target is
expected to be a valid file descriptor of a cgroup v2 directory which
has the bpf controller enabled. These are the only use-cases
implemented by this patch at this point, but more can be added.

If a program of the given type already exists in the given cgroup,
the program is swapped automically, so userspace does not have to drop
an existing program first before installing a new one, which would
otherwise leave a gap in which no program is attached.

For more information on the propagation logic to subcgroups, please
refer to the bpf cgroup controller implementation.

The API is guarded by CAP_NET_ADMIN.

Signed-off-by: default avatarDaniel Mack <daniel@zonque.org>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 30070984
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ enum bpf_cmd {
	BPF_PROG_LOAD,
	BPF_OBJ_PIN,
	BPF_OBJ_GET,
	BPF_PROG_ATTACH,
	BPF_PROG_DETACH,
};

enum bpf_map_type {
@@ -159,6 +161,12 @@ union bpf_attr {
		__aligned_u64	pathname;
		__u32		bpf_fd;
	};

	struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
		__u32		target_fd;	/* container object to attach to */
		__u32		attach_bpf_fd;	/* eBPF program to attach */
		__u32		attach_type;
	};
} __attribute__((aligned(8)));

/* BPF helper function descriptions:
+81 −0
Original line number Diff line number Diff line
@@ -835,6 +835,77 @@ static int bpf_obj_get(const union bpf_attr *attr)
	return bpf_obj_get_user(u64_to_user_ptr(attr->pathname));
}

#ifdef CONFIG_CGROUP_BPF

#define BPF_PROG_ATTACH_LAST_FIELD attach_type

static int bpf_prog_attach(const union bpf_attr *attr)
{
	struct bpf_prog *prog;
	struct cgroup *cgrp;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	if (CHECK_ATTR(BPF_PROG_ATTACH))
		return -EINVAL;

	switch (attr->attach_type) {
	case BPF_CGROUP_INET_INGRESS:
	case BPF_CGROUP_INET_EGRESS:
		prog = bpf_prog_get_type(attr->attach_bpf_fd,
					 BPF_PROG_TYPE_CGROUP_SKB);
		if (IS_ERR(prog))
			return PTR_ERR(prog);

		cgrp = cgroup_get_from_fd(attr->target_fd);
		if (IS_ERR(cgrp)) {
			bpf_prog_put(prog);
			return PTR_ERR(cgrp);
		}

		cgroup_bpf_update(cgrp, prog, attr->attach_type);
		cgroup_put(cgrp);
		break;

	default:
		return -EINVAL;
	}

	return 0;
}

#define BPF_PROG_DETACH_LAST_FIELD attach_type

static int bpf_prog_detach(const union bpf_attr *attr)
{
	struct cgroup *cgrp;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	if (CHECK_ATTR(BPF_PROG_DETACH))
		return -EINVAL;

	switch (attr->attach_type) {
	case BPF_CGROUP_INET_INGRESS:
	case BPF_CGROUP_INET_EGRESS:
		cgrp = cgroup_get_from_fd(attr->target_fd);
		if (IS_ERR(cgrp))
			return PTR_ERR(cgrp);

		cgroup_bpf_update(cgrp, NULL, attr->attach_type);
		cgroup_put(cgrp);
		break;

	default:
		return -EINVAL;
	}

	return 0;
}
#endif /* CONFIG_CGROUP_BPF */

SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
{
	union bpf_attr attr = {};
@@ -901,6 +972,16 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
	case BPF_OBJ_GET:
		err = bpf_obj_get(&attr);
		break;

#ifdef CONFIG_CGROUP_BPF
	case BPF_PROG_ATTACH:
		err = bpf_prog_attach(&attr);
		break;
	case BPF_PROG_DETACH:
		err = bpf_prog_detach(&attr);
		break;
#endif

	default:
		err = -EINVAL;
		break;