mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									324bda9e6c
								
							
						
					
					
						commit
						468e2f64d2
					
				
					 7 changed files with 148 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -44,12 +44,16 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		|||
			enum bpf_attach_type type, u32 flags);
 | 
			
		||||
int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		||||
			enum bpf_attach_type type, u32 flags);
 | 
			
		||||
int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
 | 
			
		||||
		       union bpf_attr __user *uattr);
 | 
			
		||||
 | 
			
		||||
/* Wrapper for __cgroup_bpf_*() protected by cgroup_mutex */
 | 
			
		||||
int cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		||||
		      enum bpf_attach_type type, u32 flags);
 | 
			
		||||
int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		||||
		      enum bpf_attach_type type, u32 flags);
 | 
			
		||||
int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
 | 
			
		||||
		     union bpf_attr __user *uattr);
 | 
			
		||||
 | 
			
		||||
int __cgroup_bpf_run_filter_skb(struct sock *sk,
 | 
			
		||||
				struct sk_buff *skb,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -260,6 +260,9 @@ struct bpf_prog_array {
 | 
			
		|||
 | 
			
		||||
struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags);
 | 
			
		||||
void bpf_prog_array_free(struct bpf_prog_array __rcu *progs);
 | 
			
		||||
int bpf_prog_array_length(struct bpf_prog_array __rcu *progs);
 | 
			
		||||
int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
 | 
			
		||||
				__u32 __user *prog_ids, u32 cnt);
 | 
			
		||||
 | 
			
		||||
#define BPF_PROG_RUN_ARRAY(array, ctx, func)		\
 | 
			
		||||
	({						\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,6 +92,7 @@ enum bpf_cmd {
 | 
			
		|||
	BPF_PROG_GET_FD_BY_ID,
 | 
			
		||||
	BPF_MAP_GET_FD_BY_ID,
 | 
			
		||||
	BPF_OBJ_GET_INFO_BY_FD,
 | 
			
		||||
	BPF_PROG_QUERY,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum bpf_map_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +212,9 @@ enum bpf_attach_type {
 | 
			
		|||
/* Specify numa node during map creation */
 | 
			
		||||
#define BPF_F_NUMA_NODE		(1U << 2)
 | 
			
		||||
 | 
			
		||||
/* flags for BPF_PROG_QUERY */
 | 
			
		||||
#define BPF_F_QUERY_EFFECTIVE	(1U << 0)
 | 
			
		||||
 | 
			
		||||
#define BPF_OBJ_NAME_LEN 16U
 | 
			
		||||
 | 
			
		||||
union bpf_attr {
 | 
			
		||||
| 
						 | 
				
			
			@ -289,6 +293,15 @@ union bpf_attr {
 | 
			
		|||
		__u32		info_len;
 | 
			
		||||
		__aligned_u64	info;
 | 
			
		||||
	} info;
 | 
			
		||||
 | 
			
		||||
	struct { /* anonymous struct used by BPF_PROG_QUERY command */
 | 
			
		||||
		__u32		target_fd;	/* container object to query */
 | 
			
		||||
		__u32		attach_type;
 | 
			
		||||
		__u32		query_flags;
 | 
			
		||||
		__u32		attach_flags;
 | 
			
		||||
		__aligned_u64	prog_ids;
 | 
			
		||||
		__u32		prog_cnt;
 | 
			
		||||
	} query;
 | 
			
		||||
} __attribute__((aligned(8)));
 | 
			
		||||
 | 
			
		||||
/* BPF helper function descriptions:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -384,6 +384,52 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Must be called with cgroup_mutex held to avoid races. */
 | 
			
		||||
int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
 | 
			
		||||
		       union bpf_attr __user *uattr)
 | 
			
		||||
{
 | 
			
		||||
	__u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids);
 | 
			
		||||
	enum bpf_attach_type type = attr->query.attach_type;
 | 
			
		||||
	struct list_head *progs = &cgrp->bpf.progs[type];
 | 
			
		||||
	u32 flags = cgrp->bpf.flags[type];
 | 
			
		||||
	int cnt, ret = 0, i;
 | 
			
		||||
 | 
			
		||||
	if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE)
 | 
			
		||||
		cnt = bpf_prog_array_length(cgrp->bpf.effective[type]);
 | 
			
		||||
	else
 | 
			
		||||
		cnt = prog_list_length(progs);
 | 
			
		||||
 | 
			
		||||
	if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags)))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
	if (copy_to_user(&uattr->query.prog_cnt, &cnt, sizeof(cnt)))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
	if (attr->query.prog_cnt == 0 || !prog_ids || !cnt)
 | 
			
		||||
		/* return early if user requested only program count + flags */
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (attr->query.prog_cnt < cnt) {
 | 
			
		||||
		cnt = attr->query.prog_cnt;
 | 
			
		||||
		ret = -ENOSPC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (attr->query.query_flags & BPF_F_QUERY_EFFECTIVE) {
 | 
			
		||||
		return bpf_prog_array_copy_to_user(cgrp->bpf.effective[type],
 | 
			
		||||
						   prog_ids, cnt);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct bpf_prog_list *pl;
 | 
			
		||||
		u32 id;
 | 
			
		||||
 | 
			
		||||
		i = 0;
 | 
			
		||||
		list_for_each_entry(pl, progs, node) {
 | 
			
		||||
			id = pl->prog->aux->id;
 | 
			
		||||
			if (copy_to_user(prog_ids + i, &id, sizeof(id)))
 | 
			
		||||
				return -EFAULT;
 | 
			
		||||
			if (++i == cnt)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering
 | 
			
		||||
 * @sk: The socket sending or receiving traffic
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1412,6 +1412,44 @@ void bpf_prog_array_free(struct bpf_prog_array __rcu *progs)
 | 
			
		|||
	kfree_rcu(progs, rcu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bpf_prog_array_length(struct bpf_prog_array __rcu *progs)
 | 
			
		||||
{
 | 
			
		||||
	struct bpf_prog **prog;
 | 
			
		||||
	u32 cnt = 0;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	prog = rcu_dereference(progs)->progs;
 | 
			
		||||
	for (; *prog; prog++)
 | 
			
		||||
		cnt++;
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return cnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
 | 
			
		||||
				__u32 __user *prog_ids, u32 cnt)
 | 
			
		||||
{
 | 
			
		||||
	struct bpf_prog **prog;
 | 
			
		||||
	u32 i = 0, id;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	prog = rcu_dereference(progs)->progs;
 | 
			
		||||
	for (; *prog; prog++) {
 | 
			
		||||
		id = (*prog)->aux->id;
 | 
			
		||||
		if (copy_to_user(prog_ids + i, &id, sizeof(id))) {
 | 
			
		||||
			rcu_read_unlock();
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
		}
 | 
			
		||||
		if (++i == cnt) {
 | 
			
		||||
			prog++;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	if (*prog)
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bpf_prog_free_deferred(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	struct bpf_prog_aux *aux;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1272,6 +1272,37 @@ static int bpf_prog_detach(const union bpf_attr *attr)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define BPF_PROG_QUERY_LAST_FIELD query.prog_cnt
 | 
			
		||||
 | 
			
		||||
static int bpf_prog_query(const union bpf_attr *attr,
 | 
			
		||||
			  union bpf_attr __user *uattr)
 | 
			
		||||
{
 | 
			
		||||
	struct cgroup *cgrp;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!capable(CAP_NET_ADMIN))
 | 
			
		||||
		return -EPERM;
 | 
			
		||||
	if (CHECK_ATTR(BPF_PROG_QUERY))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	switch (attr->query.attach_type) {
 | 
			
		||||
	case BPF_CGROUP_INET_INGRESS:
 | 
			
		||||
	case BPF_CGROUP_INET_EGRESS:
 | 
			
		||||
	case BPF_CGROUP_INET_SOCK_CREATE:
 | 
			
		||||
	case BPF_CGROUP_SOCK_OPS:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	cgrp = cgroup_get_from_fd(attr->query.target_fd);
 | 
			
		||||
	if (IS_ERR(cgrp))
 | 
			
		||||
		return PTR_ERR(cgrp);
 | 
			
		||||
	ret = cgroup_bpf_query(cgrp, attr, uattr);
 | 
			
		||||
	cgroup_put(cgrp);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_CGROUP_BPF */
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		|||
	case BPF_PROG_DETACH:
 | 
			
		||||
		err = bpf_prog_detach(&attr);
 | 
			
		||||
		break;
 | 
			
		||||
	case BPF_PROG_QUERY:
 | 
			
		||||
		err = bpf_prog_query(&attr, uattr);
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	case BPF_PROG_TEST_RUN:
 | 
			
		||||
		err = bpf_prog_test_run(&attr, uattr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5761,4 +5761,14 @@ int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
 | 
			
		|||
	mutex_unlock(&cgroup_mutex);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
 | 
			
		||||
		     union bpf_attr __user *uattr)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&cgroup_mutex);
 | 
			
		||||
	ret = __cgroup_bpf_query(cgrp, attr, uattr);
 | 
			
		||||
	mutex_unlock(&cgroup_mutex);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_CGROUP_BPF */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue