History

bpf: Implement bpf_link-based cgroup BPF program attachment

Implement new sub-command to attach cgroup BPF programs and return FD-based bpf_link back on success. bpf_link, once attached to cgroup, cannot be replaced, except by owner having its FD. Cgroup bpf_link supports only BPF_F_ALLOW_MULTI semantics. Both link-based and prog-based BPF_F_ALLOW_MULTI attachments can be freely intermixed. To prevent bpf_cgroup_link from keeping cgroup alive past the point when no BPF program can be executed, implement auto-detachment of link. When cgroup_bpf_release() is called, all attached bpf_links are forced to release cgroup refcounts, but they leave bpf_link otherwise active and allocated, as well as still owning underlying bpf_prog. This is because user-space might still have FDs open and active, so bpf_link as a user-referenced object can't be freed yet. Once last active FD is closed, bpf_link will be freed and underlying bpf_prog refcount will be dropped. But cgroup refcount won't be touched, because cgroup is released already. The inherent race between bpf_cgroup_link release (from closing last FD) and cgroup_bpf_release() is resolved by both operations taking cgroup_mutex. So the only additional check required is when bpf_cgroup_link attempts to detach itself from cgroup. At that time we need to check whether there is still cgroup associated with that link. And if not, exit with success, because bpf_cgroup_link was already successfully detached.

Andrii Nakryiko committed 6 years ago

Commit af6eea51 parent e5ffcc97 files · +354 −98Browse files

Showing the changes to include/linux (2 of 7 files). Show all

Unified · Split

2 files
  1. include/linux/bpf-cgroup.h +24 −5
  2. include/linux/bpf.h +9 −1
include/linux/bpf-cgroup.h+24−5
@@ -51,9 +51,18 @@ struct bpf_cgroup_storage { · 50 unmodified lines
51 struct rcu_head rcu;51 struct rcu_head rcu;
52};52};
53 53
54struct bpf_cgroup_link {
55 struct bpf_link link;
56 struct cgroup *cgroup;
57 enum bpf_attach_type type;
58};
59
60extern const struct bpf_link_ops bpf_cgroup_link_lops;
61
54struct bpf_prog_list {62struct bpf_prog_list {
55 struct list_head node;63 struct list_head node;
56 struct bpf_prog *prog;64 struct bpf_prog *prog;
65 struct bpf_cgroup_link *link;
57 struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE];66 struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE];
58};67};
59 68
@@ -84,20 +93,23 @@ struct cgroup_bpf { · 24 unmodified lines
84int cgroup_bpf_inherit(struct cgroup *cgrp);93int cgroup_bpf_inherit(struct cgroup *cgrp);
85void cgroup_bpf_offline(struct cgroup *cgrp);94void cgroup_bpf_offline(struct cgroup *cgrp);
86 95
87int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,96int __cgroup_bpf_attach(struct cgroup *cgrp,
88 struct bpf_prog *replace_prog,97 struct bpf_prog *prog, struct bpf_prog *replace_prog,
98 struct bpf_cgroup_link *link,
89 enum bpf_attach_type type, u32 flags);99 enum bpf_attach_type type, u32 flags);
90int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,100int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
101 struct bpf_cgroup_link *link,
91 enum bpf_attach_type type);102 enum bpf_attach_type type);
92int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,103int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
93 union bpf_attr __user *uattr);104 union bpf_attr __user *uattr);
94 105
95/* Wrapper for __cgroup_bpf_*() protected by cgroup_mutex */106/* Wrapper for __cgroup_bpf_*() protected by cgroup_mutex */
96int cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,107int cgroup_bpf_attach(struct cgroup *cgrp,
97 struct bpf_prog *replace_prog, enum bpf_attach_type type,108 struct bpf_prog *prog, struct bpf_prog *replace_prog,
109 struct bpf_cgroup_link *link, enum bpf_attach_type type,
98 u32 flags);110 u32 flags);
99int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,111int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
100 enum bpf_attach_type type, u32 flags);112 enum bpf_attach_type type);
101int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,113int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
102 union bpf_attr __user *uattr);114 union bpf_attr __user *uattr);
103 115
@@ -332,6 +344,7 @@ int cgroup_bpf_prog_attach(const union bpf_attr *attr, · 228 unmodified lines
332 enum bpf_prog_type ptype, struct bpf_prog *prog);344 enum bpf_prog_type ptype, struct bpf_prog *prog);
333int cgroup_bpf_prog_detach(const union bpf_attr *attr,345int cgroup_bpf_prog_detach(const union bpf_attr *attr,
334 enum bpf_prog_type ptype);346 enum bpf_prog_type ptype);
347int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
335int cgroup_bpf_prog_query(const union bpf_attr *attr,348int cgroup_bpf_prog_query(const union bpf_attr *attr,
336 union bpf_attr __user *uattr);349 union bpf_attr __user *uattr);
337#else350#else
@@ -354,6 +367,12 @@ static inline int cgroup_bpf_prog_detach(const union bpf_attr *attr, · 16 unmodified lines
354 return -EINVAL;367 return -EINVAL;
355}368}
356 369
370static inline int cgroup_bpf_link_attach(const union bpf_attr *attr,
371 struct bpf_prog *prog)
372{
373 return -EINVAL;
374}
375
357static inline int cgroup_bpf_prog_query(const union bpf_attr *attr,376static inline int cgroup_bpf_prog_query(const union bpf_attr *attr,
358 union bpf_attr __user *uattr)377 union bpf_attr __user *uattr)
359{378{
include/linux/bpf.h+9−1
@@ -1082,15 +1082,23 @@ extern int sysctl_unprivileged_bpf_disabled; · 1081 unmodified lines
1082int bpf_map_new_fd(struct bpf_map *map, int flags);1082int bpf_map_new_fd(struct bpf_map *map, int flags);
1083int bpf_prog_new_fd(struct bpf_prog *prog);1083int bpf_prog_new_fd(struct bpf_prog *prog);
1084 1084
1085struct bpf_link;1085struct bpf_link {
1086 atomic64_t refcnt;
1087 const struct bpf_link_ops *ops;
1088 struct bpf_prog *prog;
1089 struct work_struct work;
1090};
1086 1091
1087struct bpf_link_ops {1092struct bpf_link_ops {
1088 void (*release)(struct bpf_link *link);1093 void (*release)(struct bpf_link *link);
1089 void (*dealloc)(struct bpf_link *link);1094 void (*dealloc)(struct bpf_link *link);
1095
1090};1096};
1091 1097
1092void bpf_link_init(struct bpf_link *link, const struct bpf_link_ops *ops,1098void bpf_link_init(struct bpf_link *link, const struct bpf_link_ops *ops,
1093 struct bpf_prog *prog);1099 struct bpf_prog *prog);
1100void bpf_link_cleanup(struct bpf_link *link, struct file *link_file,
1101 int link_fd);
1094void bpf_link_inc(struct bpf_link *link);1102void bpf_link_inc(struct bpf_link *link);
1095void bpf_link_put(struct bpf_link *link);1103void bpf_link_put(struct bpf_link *link);
1096int bpf_link_new_fd(struct bpf_link *link);1104int bpf_link_new_fd(struct bpf_link *link);