Skip to content

Commit 7f67763

Browse files
4astdavem330
authored andcommitted
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: 3007098 ("cgroup: add support for eBPF programs") Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Acked-by: Tejun Heo <[email protected]> Acked-by: Daniel Mack <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e722af6 commit 7f67763

File tree

11 files changed

+151
-38
lines changed

11 files changed

+151
-38
lines changed

include/linux/bpf-cgroup.h

+6-7
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,19 @@ struct cgroup_bpf {
2121
*/
2222
struct bpf_prog *prog[MAX_BPF_ATTACH_TYPE];
2323
struct bpf_prog __rcu *effective[MAX_BPF_ATTACH_TYPE];
24+
bool disallow_override[MAX_BPF_ATTACH_TYPE];
2425
};
2526

2627
void cgroup_bpf_put(struct cgroup *cgrp);
2728
void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent);
2829

29-
void __cgroup_bpf_update(struct cgroup *cgrp,
30-
struct cgroup *parent,
31-
struct bpf_prog *prog,
32-
enum bpf_attach_type type);
30+
int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent,
31+
struct bpf_prog *prog, enum bpf_attach_type type,
32+
bool overridable);
3333

3434
/* Wrapper for __cgroup_bpf_update() protected by cgroup_mutex */
35-
void cgroup_bpf_update(struct cgroup *cgrp,
36-
struct bpf_prog *prog,
37-
enum bpf_attach_type type);
35+
int cgroup_bpf_update(struct cgroup *cgrp, struct bpf_prog *prog,
36+
enum bpf_attach_type type, bool overridable);
3837

3938
int __cgroup_bpf_run_filter_skb(struct sock *sk,
4039
struct sk_buff *skb,

include/uapi/linux/bpf.h

+7
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ enum bpf_attach_type {
116116

117117
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
118118

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+
119125
#define BPF_PSEUDO_MAP_FD 1
120126

121127
/* flags for BPF_MAP_UPDATE_ELEM command */
@@ -171,6 +177,7 @@ union bpf_attr {
171177
__u32 target_fd; /* container object to attach to */
172178
__u32 attach_bpf_fd; /* eBPF program to attach */
173179
__u32 attach_type;
180+
__u32 attach_flags;
174181
};
175182
} __attribute__((aligned(8)));
176183

kernel/bpf/cgroup.c

+47-12
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
5252
e = rcu_dereference_protected(parent->bpf.effective[type],
5353
lockdep_is_held(&cgroup_mutex));
5454
rcu_assign_pointer(cgrp->bpf.effective[type], e);
55+
cgrp->bpf.disallow_override[type] = parent->bpf.disallow_override[type];
5556
}
5657
}
5758

@@ -82,30 +83,63 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
8283
*
8384
* Must be called with cgroup_mutex held.
8485
*/
85-
void __cgroup_bpf_update(struct cgroup *cgrp,
86-
struct cgroup *parent,
87-
struct bpf_prog *prog,
88-
enum bpf_attach_type type)
86+
int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent,
87+
struct bpf_prog *prog, enum bpf_attach_type type,
88+
bool new_overridable)
8989
{
90-
struct bpf_prog *old_prog, *effective;
90+
struct bpf_prog *old_prog, *effective = NULL;
9191
struct cgroup_subsys_state *pos;
92+
bool overridable = true;
9293

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;
94111

95-
effective = (!prog && parent) ?
96-
rcu_dereference_protected(parent->bpf.effective[type],
97-
lockdep_is_held(&cgroup_mutex)) :
98-
prog;
112+
old_prog = cgrp->bpf.prog[type];
113+
114+
if (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;
99131

100132
css_for_each_descendant_pre(pos, &cgrp->self) {
101133
struct cgroup *desc = container_of(pos, struct cgroup, self);
102134

103135
/* 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) {
105137
pos = css_rightmost_descendant(pos);
106-
else
138+
} else {
107139
rcu_assign_pointer(desc->bpf.effective[type],
108140
effective);
141+
desc->bpf.disallow_override[type] = !overridable;
142+
}
109143
}
110144

111145
if (prog)
@@ -115,6 +149,7 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
115149
bpf_prog_put(old_prog);
116150
static_branch_dec(&cgroup_bpf_enabled_key);
117151
}
152+
return 0;
118153
}
119154

120155
/**

kernel/bpf/syscall.c

+14-6
Original file line numberDiff line numberDiff line change
@@ -920,20 +920,24 @@ static int bpf_obj_get(const union bpf_attr *attr)
920920

921921
#ifdef CONFIG_CGROUP_BPF
922922

923-
#define BPF_PROG_ATTACH_LAST_FIELD attach_type
923+
#define BPF_PROG_ATTACH_LAST_FIELD attach_flags
924924

925925
static int bpf_prog_attach(const union bpf_attr *attr)
926926
{
927+
enum bpf_prog_type ptype;
927928
struct bpf_prog *prog;
928929
struct cgroup *cgrp;
929-
enum bpf_prog_type ptype;
930+
int ret;
930931

931932
if (!capable(CAP_NET_ADMIN))
932933
return -EPERM;
933934

934935
if (CHECK_ATTR(BPF_PROG_ATTACH))
935936
return -EINVAL;
936937

938+
if (attr->attach_flags & ~BPF_F_ALLOW_OVERRIDE)
939+
return -EINVAL;
940+
937941
switch (attr->attach_type) {
938942
case BPF_CGROUP_INET_INGRESS:
939943
case BPF_CGROUP_INET_EGRESS:
@@ -956,17 +960,21 @@ static int bpf_prog_attach(const union bpf_attr *attr)
956960
return PTR_ERR(cgrp);
957961
}
958962

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);
960967
cgroup_put(cgrp);
961968

962-
return 0;
969+
return ret;
963970
}
964971

965972
#define BPF_PROG_DETACH_LAST_FIELD attach_type
966973

967974
static int bpf_prog_detach(const union bpf_attr *attr)
968975
{
969976
struct cgroup *cgrp;
977+
int ret;
970978

971979
if (!capable(CAP_NET_ADMIN))
972980
return -EPERM;
@@ -982,15 +990,15 @@ static int bpf_prog_detach(const union bpf_attr *attr)
982990
if (IS_ERR(cgrp))
983991
return PTR_ERR(cgrp);
984992

985-
cgroup_bpf_update(cgrp, NULL, attr->attach_type);
993+
ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
986994
cgroup_put(cgrp);
987995
break;
988996

989997
default:
990998
return -EINVAL;
991999
}
9921000

993-
return 0;
1001+
return ret;
9941002
}
9951003
#endif /* CONFIG_CGROUP_BPF */
9961004

kernel/cgroup.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -6498,15 +6498,16 @@ static __init int cgroup_namespaces_init(void)
64986498
subsys_initcall(cgroup_namespaces_init);
64996499

65006500
#ifdef CONFIG_CGROUP_BPF
6501-
void cgroup_bpf_update(struct cgroup *cgrp,
6502-
struct bpf_prog *prog,
6503-
enum bpf_attach_type type)
6501+
int cgroup_bpf_update(struct cgroup *cgrp, struct bpf_prog *prog,
6502+
enum bpf_attach_type type, bool overridable)
65046503
{
65056504
struct cgroup *parent = cgroup_parent(cgrp);
6505+
int ret;
65066506

65076507
mutex_lock(&cgroup_mutex);
6508-
__cgroup_bpf_update(cgrp, parent, prog, type);
6508+
ret = __cgroup_bpf_update(cgrp, parent, prog, type, overridable);
65096509
mutex_unlock(&cgroup_mutex);
6510+
return ret;
65106511
}
65116512
#endif /* CONFIG_CGROUP_BPF */
65126513

samples/bpf/test_cgrp2_attach.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static int attach_filter(int cg_fd, int type, int verdict)
104104
return EXIT_FAILURE;
105105
}
106106

107-
ret = bpf_prog_attach(prog_fd, cg_fd, type);
107+
ret = bpf_prog_attach(prog_fd, cg_fd, type, 0);
108108
if (ret < 0) {
109109
printf("Failed to attach prog to cgroup: '%s'\n",
110110
strerror(errno));

samples/bpf/test_cgrp2_attach2.c

+64-4
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@ int main(int argc, char **argv)
7979
if (join_cgroup(FOO))
8080
goto err;
8181

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)) {
8383
log_err("Attaching prog to /foo");
8484
goto err;
8585
}
8686

87+
printf("Attached DROP prog. This ping in cgroup /foo should fail...\n");
8788
assert(system(PING_CMD) != 0);
8889

8990
/* Create cgroup /foo/bar, get fd, and join it */
@@ -94,24 +95,27 @@ int main(int argc, char **argv)
9495
if (join_cgroup(BAR))
9596
goto err;
9697

98+
printf("Attached DROP prog. This ping in cgroup /foo/bar should fail...\n");
9799
assert(system(PING_CMD) != 0);
98100

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)) {
100102
log_err("Attaching prog to /foo/bar");
101103
goto err;
102104
}
103105

106+
printf("Attached PASS prog. This ping in cgroup /foo/bar should pass...\n");
104107
assert(system(PING_CMD) == 0);
105108

106-
107109
if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) {
108110
log_err("Detaching program from /foo/bar");
109111
goto err;
110112
}
111113

114+
printf("Detached PASS from /foo/bar while DROP is attached to /foo.\n"
115+
"This ping in cgroup /foo/bar should fail...\n");
112116
assert(system(PING_CMD) != 0);
113117

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)) {
115119
log_err("Attaching prog to /foo/bar");
116120
goto err;
117121
}
@@ -121,8 +125,60 @@ int main(int argc, char **argv)
121125
goto err;
122126
}
123127

128+
printf("Attached PASS from /foo/bar and detached DROP from /foo.\n"
129+
"This ping in cgroup /foo/bar should pass...\n");
124130
assert(system(PING_CMD) == 0);
125131

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+
126182
goto out;
127183

128184
err:
@@ -132,5 +188,9 @@ int main(int argc, char **argv)
132188
close(foo);
133189
close(bar);
134190
cleanup_cgroup_environment();
191+
if (!rc)
192+
printf("PASS\n");
193+
else
194+
printf("FAIL\n");
135195
return rc;
136196
}

samples/bpf/test_cgrp2_sock.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ int main(int argc, char **argv)
7575
return EXIT_FAILURE;
7676
}
7777

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);
7979
if (ret < 0) {
8080
printf("Failed to attach prog to cgroup: '%s'\n",
8181
strerror(errno));

samples/bpf/test_cgrp2_sock2.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ int main(int argc, char **argv)
5555
}
5656

5757
ret = bpf_prog_attach(prog_fd[filter_id], cg_fd,
58-
BPF_CGROUP_INET_SOCK_CREATE);
58+
BPF_CGROUP_INET_SOCK_CREATE, 0);
5959
if (ret < 0) {
6060
printf("Failed to attach prog to cgroup: '%s'\n",
6161
strerror(errno));

tools/lib/bpf/bpf.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,16 @@ int bpf_obj_get(const char *pathname)
168168
return sys_bpf(BPF_OBJ_GET, &attr, sizeof(attr));
169169
}
170170

171-
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type)
171+
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
172+
unsigned int flags)
172173
{
173174
union bpf_attr attr;
174175

175176
bzero(&attr, sizeof(attr));
176177
attr.target_fd = target_fd;
177178
attr.attach_bpf_fd = prog_fd;
178179
attr.attach_type = type;
180+
attr.attach_flags = flags;
179181

180182
return sys_bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
181183
}

0 commit comments

Comments
 (0)