diff options
Diffstat (limited to 'kernel/bpf/cgroup.c')
| -rw-r--r-- | kernel/bpf/cgroup.c | 216 | 
1 files changed, 146 insertions, 70 deletions
| diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index f7c00bd6f8e4..6a7d931bbc55 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -34,6 +34,8 @@ void cgroup_bpf_put(struct cgroup *cgrp)  		list_for_each_entry_safe(pl, tmp, progs, node) {  			list_del(&pl->node);  			bpf_prog_put(pl->prog); +			bpf_cgroup_storage_unlink(pl->storage); +			bpf_cgroup_storage_free(pl->storage);  			kfree(pl);  			static_branch_dec(&cgroup_bpf_enabled_key);  		} @@ -95,7 +97,7 @@ static int compute_effective_progs(struct cgroup *cgrp,  				   enum bpf_attach_type type,  				   struct bpf_prog_array __rcu **array)  { -	struct bpf_prog_array __rcu *progs; +	struct bpf_prog_array *progs;  	struct bpf_prog_list *pl;  	struct cgroup *p = cgrp;  	int cnt = 0; @@ -115,18 +117,20 @@ static int compute_effective_progs(struct cgroup *cgrp,  	cnt = 0;  	p = cgrp;  	do { -		if (cnt == 0 || (p->bpf.flags[type] & BPF_F_ALLOW_MULTI)) -			list_for_each_entry(pl, -					    &p->bpf.progs[type], node) { -				if (!pl->prog) -					continue; -				rcu_dereference_protected(progs, 1)-> -					progs[cnt++] = pl->prog; -			} -		p = cgroup_parent(p); -	} while (p); +		if (cnt > 0 && !(p->bpf.flags[type] & BPF_F_ALLOW_MULTI)) +			continue; + +		list_for_each_entry(pl, &p->bpf.progs[type], node) { +			if (!pl->prog) +				continue; + +			progs->items[cnt].prog = pl->prog; +			progs->items[cnt].cgroup_storage = pl->storage; +			cnt++; +		} +	} while ((p = cgroup_parent(p))); -	*array = progs; +	rcu_assign_pointer(*array, progs);  	return 0;  } @@ -173,6 +177,45 @@ cleanup:  	return -ENOMEM;  } +static int update_effective_progs(struct cgroup *cgrp, +				  enum bpf_attach_type type) +{ +	struct cgroup_subsys_state *css; +	int err; + +	/* allocate and recompute effective prog arrays */ +	css_for_each_descendant_pre(css, &cgrp->self) { +		struct cgroup *desc = container_of(css, struct cgroup, self); + +		err = compute_effective_progs(desc, type, &desc->bpf.inactive); +		if (err) +			goto cleanup; +	} + +	/* all allocations were successful. Activate all prog arrays */ +	css_for_each_descendant_pre(css, &cgrp->self) { +		struct cgroup *desc = container_of(css, struct cgroup, self); + +		activate_effective_progs(desc, type, desc->bpf.inactive); +		desc->bpf.inactive = NULL; +	} + +	return 0; + +cleanup: +	/* oom while computing effective. Free all computed effective arrays +	 * since they were not activated +	 */ +	css_for_each_descendant_pre(css, &cgrp->self) { +		struct cgroup *desc = container_of(css, struct cgroup, self); + +		bpf_prog_array_free(desc->bpf.inactive); +		desc->bpf.inactive = NULL; +	} + +	return err; +} +  #define BPF_CGROUP_MAX_PROGS 64  /** @@ -189,7 +232,7 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,  {  	struct list_head *progs = &cgrp->bpf.progs[type];  	struct bpf_prog *old_prog = NULL; -	struct cgroup_subsys_state *css; +	struct bpf_cgroup_storage *storage, *old_storage = NULL;  	struct bpf_prog_list *pl;  	bool pl_was_allocated;  	int err; @@ -211,72 +254,71 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,  	if (prog_list_length(progs) >= BPF_CGROUP_MAX_PROGS)  		return -E2BIG; +	storage = bpf_cgroup_storage_alloc(prog); +	if (IS_ERR(storage)) +		return -ENOMEM; +  	if (flags & BPF_F_ALLOW_MULTI) { -		list_for_each_entry(pl, progs, node) -			if (pl->prog == prog) +		list_for_each_entry(pl, progs, node) { +			if (pl->prog == prog) {  				/* disallow attaching the same prog twice */ +				bpf_cgroup_storage_free(storage);  				return -EINVAL; +			} +		}  		pl = kmalloc(sizeof(*pl), GFP_KERNEL); -		if (!pl) +		if (!pl) { +			bpf_cgroup_storage_free(storage);  			return -ENOMEM; +		} +  		pl_was_allocated = true;  		pl->prog = prog; +		pl->storage = storage;  		list_add_tail(&pl->node, progs);  	} else {  		if (list_empty(progs)) {  			pl = kmalloc(sizeof(*pl), GFP_KERNEL); -			if (!pl) +			if (!pl) { +				bpf_cgroup_storage_free(storage);  				return -ENOMEM; +			}  			pl_was_allocated = true;  			list_add_tail(&pl->node, progs);  		} else {  			pl = list_first_entry(progs, typeof(*pl), node);  			old_prog = pl->prog; +			old_storage = pl->storage; +			bpf_cgroup_storage_unlink(old_storage);  			pl_was_allocated = false;  		}  		pl->prog = prog; +		pl->storage = storage;  	}  	cgrp->bpf.flags[type] = flags; -	/* allocate and recompute effective prog arrays */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		err = compute_effective_progs(desc, type, &desc->bpf.inactive); -		if (err) -			goto cleanup; -	} - -	/* all allocations were successful. Activate all prog arrays */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		activate_effective_progs(desc, type, desc->bpf.inactive); -		desc->bpf.inactive = NULL; -	} +	err = update_effective_progs(cgrp, type); +	if (err) +		goto cleanup;  	static_branch_inc(&cgroup_bpf_enabled_key); +	if (old_storage) +		bpf_cgroup_storage_free(old_storage);  	if (old_prog) {  		bpf_prog_put(old_prog);  		static_branch_dec(&cgroup_bpf_enabled_key);  	} +	bpf_cgroup_storage_link(storage, cgrp, type);  	return 0;  cleanup: -	/* oom while computing effective. Free all computed effective arrays -	 * since they were not activated -	 */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		bpf_prog_array_free(desc->bpf.inactive); -		desc->bpf.inactive = NULL; -	} -  	/* and cleanup the prog list */  	pl->prog = old_prog; +	bpf_cgroup_storage_free(pl->storage); +	pl->storage = old_storage; +	bpf_cgroup_storage_link(old_storage, cgrp, type);  	if (pl_was_allocated) {  		list_del(&pl->node);  		kfree(pl); @@ -299,7 +341,6 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,  	struct list_head *progs = &cgrp->bpf.progs[type];  	u32 flags = cgrp->bpf.flags[type];  	struct bpf_prog *old_prog = NULL; -	struct cgroup_subsys_state *css;  	struct bpf_prog_list *pl;  	int err; @@ -338,25 +379,14 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,  		pl->prog = NULL;  	} -	/* allocate and recompute effective prog arrays */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		err = compute_effective_progs(desc, type, &desc->bpf.inactive); -		if (err) -			goto cleanup; -	} - -	/* all allocations were successful. Activate all prog arrays */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		activate_effective_progs(desc, type, desc->bpf.inactive); -		desc->bpf.inactive = NULL; -	} +	err = update_effective_progs(cgrp, type); +	if (err) +		goto cleanup;  	/* now can actually delete it from this cgroup list */  	list_del(&pl->node); +	bpf_cgroup_storage_unlink(pl->storage); +	bpf_cgroup_storage_free(pl->storage);  	kfree(pl);  	if (list_empty(progs))  		/* last program was detached, reset flags to zero */ @@ -367,16 +397,6 @@ int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,  	return 0;  cleanup: -	/* oom while computing effective. Free all computed effective arrays -	 * since they were not activated -	 */ -	css_for_each_descendant_pre(css, &cgrp->self) { -		struct cgroup *desc = container_of(css, struct cgroup, self); - -		bpf_prog_array_free(desc->bpf.inactive); -		desc->bpf.inactive = NULL; -	} -  	/* and restore back old_prog */  	pl->prog = old_prog;  	return err; @@ -428,6 +448,60 @@ int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,  	return ret;  } +int cgroup_bpf_prog_attach(const union bpf_attr *attr, +			   enum bpf_prog_type ptype, struct bpf_prog *prog) +{ +	struct cgroup *cgrp; +	int ret; + +	cgrp = cgroup_get_from_fd(attr->target_fd); +	if (IS_ERR(cgrp)) +		return PTR_ERR(cgrp); + +	ret = cgroup_bpf_attach(cgrp, prog, attr->attach_type, +				attr->attach_flags); +	cgroup_put(cgrp); +	return ret; +} + +int cgroup_bpf_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype) +{ +	struct bpf_prog *prog; +	struct cgroup *cgrp; +	int ret; + +	cgrp = cgroup_get_from_fd(attr->target_fd); +	if (IS_ERR(cgrp)) +		return PTR_ERR(cgrp); + +	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); +	if (IS_ERR(prog)) +		prog = NULL; + +	ret = cgroup_bpf_detach(cgrp, prog, attr->attach_type, 0); +	if (prog) +		bpf_prog_put(prog); + +	cgroup_put(cgrp); +	return ret; +} + +int cgroup_bpf_prog_query(const union bpf_attr *attr, +			  union bpf_attr __user *uattr) +{ +	struct cgroup *cgrp; +	int ret; + +	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; +} +  /**   * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering   * @sk: The socket sending or receiving traffic @@ -601,6 +675,8 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)  		return &bpf_map_delete_elem_proto;  	case BPF_FUNC_get_current_uid_gid:  		return &bpf_get_current_uid_gid_proto; +	case BPF_FUNC_get_local_storage: +		return &bpf_get_local_storage_proto;  	case BPF_FUNC_trace_printk:  		if (capable(CAP_SYS_ADMIN))  			return bpf_get_trace_printk_proto(); |