summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2017-02-10 23:28:24 -0500
committerDavid S. Miller <davem@davemloft.net>2017-02-12 21:52:19 -0500
commit7f677633379b4abb3281cdbe7e7006f049305c03 (patch)
tree1e5e662e792467d09f8a4ebf5b96b2baa333ae25
parente722af6391949e8851310441bb0cec157d25611d (diff)
bpf: introduce BPF_F_ALLOW_OVERRIDE flag
If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command to the given cgroup the descendent cgroup will be able to override effective bpf program that was inherited from this cgroup. By default it's not passed, therefore override is disallowed. Examples: 1. prog X attached to /A with default prog Y fails to attach to /A/B and /A/B/C Everything under /A runs prog X 2. prog X attached to /A with allow_override. prog Y fails to attach to /A/B with default (non-override) prog M attached to /A/B with allow_override. Everything under /A/B runs prog M only. 3. prog X attached to /A with allow_override. prog Y fails to attach to /A with default. The user has to detach first to switch the mode. In the future this behavior may be extended with a chain of non-overridable programs. Also fix the bug where detach from cgroup where nothing is attached was not throwing error. Return ENOENT in such case. Add several testcases and adjust libbpf. Fixes: 3007098494be ("cgroup: add support for eBPF programs") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Tejun Heo <tj@kernel.org> Acked-by: Daniel Mack <daniel@zonque.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/bpf-cgroup.h13
-rw-r--r--include/uapi/linux/bpf.h7
-rw-r--r--kernel/bpf/cgroup.c59
-rw-r--r--kernel/bpf/syscall.c20
-rw-r--r--kernel/cgroup.c9
-rw-r--r--samples/bpf/test_cgrp2_attach.c2
-rw-r--r--samples/bpf/test_cgrp2_attach2.c68
-rw-r--r--samples/bpf/test_cgrp2_sock.c2
-rw-r--r--samples/bpf/test_cgrp2_sock2.c2
-rw-r--r--tools/lib/bpf/bpf.c4
-rw-r--r--tools/lib/bpf/bpf.h3
11 files changed, 151 insertions, 38 deletions
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index 92bc89ae7e20..c970a25d2a49 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -21,20 +21,19 @@ struct cgroup_bpf {
21 */ 21 */
22 struct bpf_prog *prog[MAX_BPF_ATTACH_TYPE]; 22 struct bpf_prog *prog[MAX_BPF_ATTACH_TYPE];
23 struct bpf_prog __rcu *effective[MAX_BPF_ATTACH_TYPE]; 23 struct bpf_prog __rcu *effective[MAX_BPF_ATTACH_TYPE];
24 bool disallow_override[MAX_BPF_ATTACH_TYPE];
24}; 25};
25 26
26void cgroup_bpf_put(struct cgroup *cgrp); 27void cgroup_bpf_put(struct cgroup *cgrp);
27void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent); 28void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent);
28 29
29void __cgroup_bpf_update(struct cgroup *cgrp, 30int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent,
30 struct cgroup *parent, 31 struct bpf_prog *prog, enum bpf_attach_type type,
31 struct bpf_prog *prog, 32 bool overridable);
32 enum bpf_attach_type type);
33 33
34/* Wrapper for __cgroup_bpf_update() protected by cgroup_mutex */ 34/* Wrapper for __cgroup_bpf_update() protected by cgroup_mutex */
35void cgroup_bpf_update(struct cgroup *cgrp, 35int cgroup_bpf_update(struct cgroup *cgrp, struct bpf_prog *prog,
36 struct bpf_prog *prog, 36 enum bpf_attach_type type, bool overridable);
37 enum bpf_attach_type type);
38 37
39int __cgroup_bpf_run_filter_skb(struct sock *sk, 38int __cgroup_bpf_run_filter_skb(struct sock *sk,
40 struct sk_buff *skb, 39 struct sk_buff *skb,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0eb0e87dbe9f..d2b0ac799d03 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -116,6 +116,12 @@ enum bpf_attach_type {
116 116
117#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE 117#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
118 118
119/* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command
120 * to the given target_fd cgroup the descendent cgroup will be able to
121 * override effective bpf program that was inherited from this cgroup
122 */
123#define BPF_F_ALLOW_OVERRIDE (1U << 0)
124
119#define BPF_PSEUDO_MAP_FD 1 125#define BPF_PSEUDO_MAP_FD 1
120 126
121/* flags for BPF_MAP_UPDATE_ELEM command */ 127/* flags for BPF_MAP_UPDATE_ELEM command */
@@ -171,6 +177,7 @@ union bpf_attr {
171 __u32 target_fd; /* container object to attach to */ 177 __u32 target_fd; /* container object to attach to */
172 __u32 attach_bpf_fd; /* eBPF program to attach */ 178 __u32 attach_bpf_fd; /* eBPF program to attach */
173 __u32 attach_type; 179 __u32 attach_type;
180 __u32 attach_flags;
174 }; 181 };
175} __attribute__((aligned(8))); 182} __attribute__((aligned(8)));
176 183
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index a515f7b007c6..da0f53690295 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -52,6 +52,7 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
52 e = rcu_dereference_protected(parent->bpf.effective[type], 52 e = rcu_dereference_protected(parent->bpf.effective[type],
53 lockdep_is_held(&cgroup_mutex)); 53 lockdep_is_held(&cgroup_mutex));
54 rcu_assign_pointer(cgrp->bpf.effective[type], e); 54 rcu_assign_pointer(cgrp->bpf.effective[type], e);
55 cgrp->bpf.disallow_override[type] = parent->bpf.disallow_override[type];
55 } 56 }
56} 57}
57 58
@@ -82,30 +83,63 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
82 * 83 *
83 * Must be called with cgroup_mutex held. 84 * Must be called with cgroup_mutex held.
84 */ 85 */
85void __cgroup_bpf_update(struct cgroup *cgrp, 86int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent,
86 struct cgroup *parent, 87 struct bpf_prog *prog, enum bpf_attach_type type,
87 struct bpf_prog *prog, 88 bool new_overridable)
88 enum bpf_attach_type type)
89{ 89{
90 struct bpf_prog *old_prog, *effective; 90 struct bpf_prog *old_prog, *effective = NULL;
91 struct cgroup_subsys_state *pos; 91 struct cgroup_subsys_state *pos;
92 bool overridable = true;
92 93
93 old_prog = xchg(cgrp->bpf.prog + type, prog); 94 if (parent) {
95 overridable = !parent->bpf.disallow_override[type];
96 effective = rcu_dereference_protected(parent->bpf.effective[type],
97 lockdep_is_held(&cgroup_mutex));
98 }
99
100 if (prog && effective && !overridable)
101 /* if parent has non-overridable prog attached, disallow
102 * attaching new programs to descendent cgroup
103 */
104 return -EPERM;
105
106 if (prog && effective && overridable != new_overridable)
107 /* if parent has overridable prog attached, only
108 * allow overridable programs in descendent cgroup
109 */
110 return -EPERM;
94 111
95 effective = (!prog && parent) ? 112 old_prog = cgrp->bpf.prog[type];
96 rcu_dereference_protected(parent->bpf.effective[type], 113
97 lockdep_is_held(&cgroup_mutex)) : 114 if (prog) {
98 prog; 115 overridable = new_overridable;
116 effective = prog;
117 if (old_prog &&
118 cgrp->bpf.disallow_override[type] == new_overridable)
119 /* disallow attaching non-overridable on top
120 * of existing overridable in this cgroup
121 * and vice versa
122 */
123 return -EPERM;
124 }
125
126 if (!prog && !old_prog)
127 /* report error when trying to detach and nothing is attached */
128 return -ENOENT;
129
130 cgrp->bpf.prog[type] = prog;
99 131
100 css_for_each_descendant_pre(pos, &cgrp->self) { 132 css_for_each_descendant_pre(pos, &cgrp->self) {
101 struct cgroup *desc = container_of(pos, struct cgroup, self); 133 struct cgroup *desc = container_of(pos, struct cgroup, self);
102 134
103 /* skip the subtree if the descendant has its own program */ 135 /* skip the subtree if the descendant has its own program */
104 if (desc->bpf.prog[type] && desc != cgrp) 136 if (desc->bpf.prog[type] && desc != cgrp) {
105 pos = css_rightmost_descendant(pos); 137 pos = css_rightmost_descendant(pos);
106 else 138 } else {
107 rcu_assign_pointer(desc->bpf.effective[type], 139 rcu_assign_pointer(desc->bpf.effective[type],
108 effective); 140 effective);
141 desc->bpf.disallow_override[type] = !overridable;
142 }
109 } 143 }
110 144
111 if (prog) 145 if (prog)
@@ -115,6 +149,7 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
115 bpf_prog_put(old_prog); 149 bpf_prog_put(old_prog);
116 static_branch_dec(&cgroup_bpf_enabled_key); 150 static_branch_dec(&cgroup_bpf_enabled_key);
117 } 151 }
152 return 0;
118} 153}
119 154
120/** 155/**
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 19b6129eab23..bbb016adbaeb 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -920,13 +920,14 @@ static int bpf_obj_get(const union bpf_attr *attr)
920 920
921#ifdef CONFIG_CGROUP_BPF 921#ifdef CONFIG_CGROUP_BPF
922 922
923#define BPF_PROG_ATTACH_LAST_FIELD attach_type 923#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
924 924
925static int bpf_prog_attach(const union bpf_attr *attr) 925static int bpf_prog_attach(const union bpf_attr *attr)
926{ 926{
927 enum bpf_prog_type ptype;
927 struct bpf_prog *prog; 928 struct bpf_prog *prog;
928 struct cgroup *cgrp; 929 struct cgroup *cgrp;
929 enum bpf_prog_type ptype; 930 int ret;
930 931
931 if (!capable(CAP_NET_ADMIN)) 932 if (!capable(CAP_NET_ADMIN))
932 return -EPERM; 933 return -EPERM;
@@ -934,6 +935,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
934 if (CHECK_ATTR(BPF_PROG_ATTACH)) 935 if (CHECK_ATTR(BPF_PROG_ATTACH))
935 return -EINVAL; 936 return -EINVAL;
936 937
938 if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE)
939 return -EINVAL;
940
937 switch (attr->attach_type) { 941 switch (attr->attach_type) {
938 case BPF_CGROUP_INET_INGRESS: 942 case BPF_CGROUP_INET_INGRESS:
939 case BPF_CGROUP_INET_EGRESS: 943 case BPF_CGROUP_INET_EGRESS:
@@ -956,10 +960,13 @@ static int bpf_prog_attach(const union bpf_attr *attr)
956 return PTR_ERR(cgrp); 960 return PTR_ERR(cgrp);
957 } 961 }
958 962
959 cgroup_bpf_update(cgrp, prog, attr->attach_type); 963 ret = cgroup_bpf_update(cgrp, prog, attr->attach_type,
964 attr->attach_flags & BPF_F_ALLOW_OVERRIDE);
965 if (ret)
966 bpf_prog_put(prog);
960 cgroup_put(cgrp); 967 cgroup_put(cgrp);
961 968
962 return 0; 969 return ret;
963} 970}
964 971
965#define BPF_PROG_DETACH_LAST_FIELD attach_type 972#define BPF_PROG_DETACH_LAST_FIELD attach_type
@@ -967,6 +974,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
967static int bpf_prog_detach(const union bpf_attr *attr) 974static int bpf_prog_detach(const union bpf_attr *attr)
968{ 975{
969 struct cgroup *cgrp; 976 struct cgroup *cgrp;
977 int ret;
970 978
971 if (!capable(CAP_NET_ADMIN)) 979 if (!capable(CAP_NET_ADMIN))
972 return -EPERM; 980 return -EPERM;
@@ -982,7 +990,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
982 if (IS_ERR(cgrp)) 990 if (IS_ERR(cgrp))
983 return PTR_ERR(cgrp); 991 return PTR_ERR(cgrp);
984 992
985 cgroup_bpf_update(cgrp, NULL, attr->attach_type); 993 ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
986 cgroup_put(cgrp); 994 cgroup_put(cgrp);
987 break; 995 break;
988 996
@@ -990,7 +998,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
990 return -EINVAL; 998 return -EINVAL;
991 } 999 }
992 1000
993 return 0; 1001 return ret;
994} 1002}
995#endif /* CONFIG_CGROUP_BPF */ 1003#endif /* CONFIG_CGROUP_BPF */
996 1004
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 688dd02af985..53bbca7c4859 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6498,15 +6498,16 @@ static __init int cgroup_namespaces_init(void)
6498subsys_initcall(cgroup_namespaces_init); 6498subsys_initcall(cgroup_namespaces_init);
6499 6499
6500#ifdef CONFIG_CGROUP_BPF 6500#ifdef CONFIG_CGROUP_BPF
6501void cgroup_bpf_update(struct cgroup *cgrp, 6501int cgroup_bpf_update(struct cgroup *cgrp, struct bpf_prog *prog,
6502 struct bpf_prog *prog, 6502 enum bpf_attach_type type, bool overridable)
6503 enum bpf_attach_type type)
6504{ 6503{
6505 struct cgroup *parent = cgroup_parent(cgrp); 6504 struct cgroup *parent = cgroup_parent(cgrp);
6505 int ret;
6506 6506
6507 mutex_lock(&cgroup_mutex); 6507 mutex_lock(&cgroup_mutex);
6508 __cgroup_bpf_update(cgrp, parent, prog, type); 6508 ret = __cgroup_bpf_update(cgrp, parent, prog, type, overridable);
6509 mutex_unlock(&cgroup_mutex); 6509 mutex_unlock(&cgroup_mutex);
6510 return ret;
6510} 6511}
6511#endif /* CONFIG_CGROUP_BPF */ 6512#endif /* CONFIG_CGROUP_BPF */
6512 6513
diff --git a/samples/bpf/test_cgrp2_attach.c b/samples/bpf/test_cgrp2_attach.c
index 504058631ffc..4bfcaf93fcf3 100644
--- a/samples/bpf/test_cgrp2_attach.c
+++ b/samples/bpf/test_cgrp2_attach.c
@@ -104,7 +104,7 @@ static int attach_filter(int cg_fd, int type, int verdict)
104 return EXIT_FAILURE; 104 return EXIT_FAILURE;
105 } 105 }
106 106
107 ret = bpf_prog_attach(prog_fd, cg_fd, type); 107 ret = bpf_prog_attach(prog_fd, cg_fd, type, 0);
108 if (ret < 0) { 108 if (ret < 0) {
109 printf("Failed to attach prog to cgroup: '%s'\n", 109 printf("Failed to attach prog to cgroup: '%s'\n",
110 strerror(errno)); 110 strerror(errno));
diff --git a/samples/bpf/test_cgrp2_attach2.c b/samples/bpf/test_cgrp2_attach2.c
index 6e69be37f87f..3049b1f26267 100644
--- a/samples/bpf/test_cgrp2_attach2.c
+++ b/samples/bpf/test_cgrp2_attach2.c
@@ -79,11 +79,12 @@ int main(int argc, char **argv)
79 if (join_cgroup(FOO)) 79 if (join_cgroup(FOO))
80 goto err; 80 goto err;
81 81
82 if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS)) { 82 if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 1)) {
83 log_err("Attaching prog to /foo"); 83 log_err("Attaching prog to /foo");
84 goto err; 84 goto err;
85 } 85 }
86 86
87 printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
87 assert(system(PING_CMD) != 0); 88 assert(system(PING_CMD) != 0);
88 89
89 /* Create cgroup /foo/bar, get fd, and join it */ 90 /* Create cgroup /foo/bar, get fd, and join it */
@@ -94,24 +95,27 @@ int main(int argc, char **argv)
94 if (join_cgroup(BAR)) 95 if (join_cgroup(BAR))
95 goto err; 96 goto err;
96 97
98 printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
97 assert(system(PING_CMD) != 0); 99 assert(system(PING_CMD) != 0);
98 100
99 if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS)) { 101 if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
100 log_err("Attaching prog to /foo/bar"); 102 log_err("Attaching prog to /foo/bar");
101 goto err; 103 goto err;
102 } 104 }
103 105
106 printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
104 assert(system(PING_CMD) == 0); 107 assert(system(PING_CMD) == 0);
105 108
106
107 if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) { 109 if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
108 log_err("Detaching program from /foo/bar"); 110 log_err("Detaching program from /foo/bar");
109 goto err; 111 goto err;
110 } 112 }
111 113
114 printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
115 "This ping in cgroup /foo/bar should fail...\n");
112 assert(system(PING_CMD) != 0); 116 assert(system(PING_CMD) != 0);
113 117
114 if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS)) { 118 if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
115 log_err("Attaching prog to /foo/bar"); 119 log_err("Attaching prog to /foo/bar");
116 goto err; 120 goto err;
117 } 121 }
@@ -121,8 +125,60 @@ int main(int argc, char **argv)
121 goto err; 125 goto err;
122 } 126 }
123 127
128 printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
129 "This ping in cgroup /foo/bar should pass...\n");
124 assert(system(PING_CMD) == 0); 130 assert(system(PING_CMD) == 0);
125 131
132 if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
133 log_err("Attaching prog to /foo/bar");
134 goto err;
135 }
136
137 if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
138 errno = 0;
139 log_err("Unexpected success attaching prog to /foo/bar");
140 goto err;
141 }
142
143 if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
144 log_err("Detaching program from /foo/bar");
145 goto err;
146 }
147
148 if (!bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) {
149 errno = 0;
150 log_err("Unexpected success in double detach from /foo");
151 goto err;
152 }
153
154 if (bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
155 log_err("Attaching non-overridable prog to /foo");
156 goto err;
157 }
158
159 if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 0)) {
160 errno = 0;
161 log_err("Unexpected success attaching non-overridable prog to /foo/bar");
162 goto err;
163 }
164
165 if (!bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS, 1)) {
166 errno = 0;
167 log_err("Unexpected success attaching overridable prog to /foo/bar");
168 goto err;
169 }
170
171 if (!bpf_prog_attach(allow_prog, foo, BPF_CGROUP_INET_EGRESS, 1)) {
172 errno = 0;
173 log_err("Unexpected success attaching overridable prog to /foo");
174 goto err;
175 }
176
177 if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS, 0)) {
178 log_err("Attaching different non-overridable prog to /foo");
179 goto err;
180 }
181
126 goto out; 182 goto out;
127 183
128err: 184err:
@@ -132,5 +188,9 @@ out:
132 close(foo); 188 close(foo);
133 close(bar); 189 close(bar);
134 cleanup_cgroup_environment(); 190 cleanup_cgroup_environment();
191 if (!rc)
192 printf("PASS\n");
193 else
194 printf("FAIL\n");
135 return rc; 195 return rc;
136} 196}
diff --git a/samples/bpf/test_cgrp2_sock.c b/samples/bpf/test_cgrp2_sock.c
index 0791b949cbe4..c3cfb23e23b5 100644
--- a/samples/bpf/test_cgrp2_sock.c
+++ b/samples/bpf/test_cgrp2_sock.c
@@ -75,7 +75,7 @@ int main(int argc, char **argv)
75 return EXIT_FAILURE; 75 return EXIT_FAILURE;
76 } 76 }
77 77
78 ret = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE); 78 ret = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE, 0);
79 if (ret < 0) { 79 if (ret < 0) {
80 printf("Failed to attach prog to cgroup: '%s'\n", 80 printf("Failed to attach prog to cgroup: '%s'\n",
81 strerror(errno)); 81 strerror(errno));
diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c
index 455ef0d06e93..db036077b644 100644
--- a/samples/bpf/test_cgrp2_sock2.c
+++ b/samples/bpf/test_cgrp2_sock2.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv)
55 } 55 }
56 56
57 ret = bpf_prog_attach(prog_fd[filter_id], cg_fd, 57 ret = bpf_prog_attach(prog_fd[filter_id], cg_fd,
58 BPF_CGROUP_INET_SOCK_CREATE); 58 BPF_CGROUP_INET_SOCK_CREATE, 0);
59 if (ret < 0) { 59 if (ret < 0) {
60 printf("Failed to attach prog to cgroup: '%s'\n", 60 printf("Failed to attach prog to cgroup: '%s'\n",
61 strerror(errno)); 61 strerror(errno));
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 3ddb58a36d3c..ae752fa4eaa7 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -168,7 +168,8 @@ int bpf_obj_get(const char *pathname)
168 return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr)); 168 return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
169} 169}
170 170
171int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type) 171int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
172 unsigned int flags)
172{ 173{
173 union bpf_attr attr; 174 union bpf_attr attr;
174 175
@@ -176,6 +177,7 @@ int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type)
176 attr.target_fd = target_fd; 177 attr.target_fd = target_fd;
177 attr.attach_bpf_fd = prog_fd; 178 attr.attach_bpf_fd = prog_fd;
178 attr.attach_type = type; 179 attr.attach_type = type;
180 attr.attach_flags = flags;
179 181
180 return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)); 182 return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
181} 183}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index a2f9853dd882..4ac6c4b84100 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -41,7 +41,8 @@ int bpf_map_delete_elem(int fd, void *key);
41int bpf_map_get_next_key(int fd, void *key, void *next_key); 41int bpf_map_get_next_key(int fd, void *key, void *next_key);
42int bpf_obj_pin(int fd, const char *pathname); 42int bpf_obj_pin(int fd, const char *pathname);
43int bpf_obj_get(const char *pathname); 43int bpf_obj_get(const char *pathname);
44int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type); 44int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type,
45 unsigned int flags);
45int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); 46int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
46 47
47 48