Blame view

kernel/bpf/cgroup.c 7.77 KB
300709849   Daniel Mack   cgroup: add suppo...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  /*
   * Functions to manage eBPF programs attached to cgroups
   *
   * Copyright (c) 2016 Daniel Mack
   *
   * This file is subject to the terms and conditions of version 2 of the GNU
   * General Public License.  See the file COPYING in the main directory of the
   * Linux distribution for more details.
   */
  
  #include <linux/kernel.h>
  #include <linux/atomic.h>
  #include <linux/cgroup.h>
  #include <linux/slab.h>
  #include <linux/bpf.h>
  #include <linux/bpf-cgroup.h>
  #include <net/sock.h>
  
  DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key);
  EXPORT_SYMBOL(cgroup_bpf_enabled_key);
  
  /**
   * cgroup_bpf_put() - put references of all bpf programs
   * @cgrp: the cgroup to modify
   */
  void cgroup_bpf_put(struct cgroup *cgrp)
  {
  	unsigned int type;
  
  	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.prog); type++) {
  		struct bpf_prog *prog = cgrp->bpf.prog[type];
  
  		if (prog) {
  			bpf_prog_put(prog);
  			static_branch_dec(&cgroup_bpf_enabled_key);
  		}
  	}
  }
  
  /**
   * cgroup_bpf_inherit() - inherit effective programs from parent
   * @cgrp: the cgroup to modify
   * @parent: the parent to inherit from
   */
  void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent)
  {
  	unsigned int type;
  
  	for (type = 0; type < ARRAY_SIZE(cgrp->bpf.effective); type++) {
  		struct bpf_prog *e;
  
  		e = rcu_dereference_protected(parent->bpf.effective[type],
  					      lockdep_is_held(&cgroup_mutex));
  		rcu_assign_pointer(cgrp->bpf.effective[type], e);
7f6776333   Alexei Starovoitov   bpf: introduce BP...
55
  		cgrp->bpf.disallow_override[type] = parent->bpf.disallow_override[type];
300709849   Daniel Mack   cgroup: add suppo...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  	}
  }
  
  /**
   * __cgroup_bpf_update() - Update the pinned program of a cgroup, and
   *                         propagate the change to descendants
   * @cgrp: The cgroup which descendants to traverse
   * @parent: The parent of @cgrp, or %NULL if @cgrp is the root
   * @prog: A new program to pin
   * @type: Type of pinning operation (ingress/egress)
   *
   * Each cgroup has a set of two pointers for bpf programs; one for eBPF
   * programs it owns, and which is effective for execution.
   *
01ae87eab   Daniel Mack   bpf: cgroup: fix ...
70
71
   * If @prog is not %NULL, this function attaches a new program to the cgroup
   * and releases the one that is currently attached, if any. @prog is then made
300709849   Daniel Mack   cgroup: add suppo...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
   * the effective program of type @type in that cgroup.
   *
   * If @prog is %NULL, the currently attached program of type @type is released,
   * and the effective program of the parent cgroup (if any) is inherited to
   * @cgrp.
   *
   * Then, the descendants of @cgrp are walked and the effective program for
   * each of them is set to the effective program of @cgrp unless the
   * descendant has its own program attached, in which case the subbranch is
   * skipped. This ensures that delegated subcgroups with own programs are left
   * untouched.
   *
   * Must be called with cgroup_mutex held.
   */
7f6776333   Alexei Starovoitov   bpf: introduce BP...
86
87
88
  int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent,
  			struct bpf_prog *prog, enum bpf_attach_type type,
  			bool new_overridable)
300709849   Daniel Mack   cgroup: add suppo...
89
  {
7f6776333   Alexei Starovoitov   bpf: introduce BP...
90
  	struct bpf_prog *old_prog, *effective = NULL;
300709849   Daniel Mack   cgroup: add suppo...
91
  	struct cgroup_subsys_state *pos;
7f6776333   Alexei Starovoitov   bpf: introduce BP...
92
  	bool overridable = true;
300709849   Daniel Mack   cgroup: add suppo...
93

7f6776333   Alexei Starovoitov   bpf: introduce BP...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  	if (parent) {
  		overridable = !parent->bpf.disallow_override[type];
  		effective = rcu_dereference_protected(parent->bpf.effective[type],
  						      lockdep_is_held(&cgroup_mutex));
  	}
  
  	if (prog && effective && !overridable)
  		/* if parent has non-overridable prog attached, disallow
  		 * attaching new programs to descendent cgroup
  		 */
  		return -EPERM;
  
  	if (prog && effective && overridable != new_overridable)
  		/* if parent has overridable prog attached, only
  		 * allow overridable programs in descendent cgroup
  		 */
  		return -EPERM;
  
  	old_prog = cgrp->bpf.prog[type];
  
  	if (prog) {
  		overridable = new_overridable;
  		effective = prog;
  		if (old_prog &&
  		    cgrp->bpf.disallow_override[type] == new_overridable)
  			/* disallow attaching non-overridable on top
  			 * of existing overridable in this cgroup
  			 * and vice versa
  			 */
  			return -EPERM;
  	}
300709849   Daniel Mack   cgroup: add suppo...
125

7f6776333   Alexei Starovoitov   bpf: introduce BP...
126
127
128
129
130
  	if (!prog && !old_prog)
  		/* report error when trying to detach and nothing is attached */
  		return -ENOENT;
  
  	cgrp->bpf.prog[type] = prog;
300709849   Daniel Mack   cgroup: add suppo...
131
132
133
134
135
  
  	css_for_each_descendant_pre(pos, &cgrp->self) {
  		struct cgroup *desc = container_of(pos, struct cgroup, self);
  
  		/* skip the subtree if the descendant has its own program */
7f6776333   Alexei Starovoitov   bpf: introduce BP...
136
  		if (desc->bpf.prog[type] && desc != cgrp) {
300709849   Daniel Mack   cgroup: add suppo...
137
  			pos = css_rightmost_descendant(pos);
7f6776333   Alexei Starovoitov   bpf: introduce BP...
138
  		} else {
300709849   Daniel Mack   cgroup: add suppo...
139
140
  			rcu_assign_pointer(desc->bpf.effective[type],
  					   effective);
7f6776333   Alexei Starovoitov   bpf: introduce BP...
141
142
  			desc->bpf.disallow_override[type] = !overridable;
  		}
300709849   Daniel Mack   cgroup: add suppo...
143
144
145
146
147
148
149
150
151
  	}
  
  	if (prog)
  		static_branch_inc(&cgroup_bpf_enabled_key);
  
  	if (old_prog) {
  		bpf_prog_put(old_prog);
  		static_branch_dec(&cgroup_bpf_enabled_key);
  	}
7f6776333   Alexei Starovoitov   bpf: introduce BP...
152
  	return 0;
300709849   Daniel Mack   cgroup: add suppo...
153
154
155
  }
  
  /**
b2cd12574   David Ahern   bpf: Refactor cgr...
156
   * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering
8f917bba0   Willem de Bruijn   bpf: pass sk to h...
157
   * @sk: The socket sending or receiving traffic
300709849   Daniel Mack   cgroup: add suppo...
158
159
160
161
162
163
164
165
166
167
168
169
   * @skb: The skb that is being sent or received
   * @type: The type of program to be exectuted
   *
   * If no socket is passed, or the socket is not of type INET or INET6,
   * this function does nothing and returns 0.
   *
   * The program type passed in via @type must be suitable for network
   * filtering. No further check is performed to assert that.
   *
   * This function will return %-EPERM if any if an attached program was found
   * and if it returned != 1 during execution. In all other cases, 0 is returned.
   */
b2cd12574   David Ahern   bpf: Refactor cgr...
170
171
172
  int __cgroup_bpf_run_filter_skb(struct sock *sk,
  				struct sk_buff *skb,
  				enum bpf_attach_type type)
300709849   Daniel Mack   cgroup: add suppo...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  {
  	struct bpf_prog *prog;
  	struct cgroup *cgrp;
  	int ret = 0;
  
  	if (!sk || !sk_fullsock(sk))
  		return 0;
  
  	if (sk->sk_family != AF_INET &&
  	    sk->sk_family != AF_INET6)
  		return 0;
  
  	cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
  
  	rcu_read_lock();
  
  	prog = rcu_dereference(cgrp->bpf.effective[type]);
  	if (prog) {
  		unsigned int offset = skb->data - skb_network_header(skb);
8f917bba0   Willem de Bruijn   bpf: pass sk to h...
192
  		struct sock *save_sk = skb->sk;
300709849   Daniel Mack   cgroup: add suppo...
193

8f917bba0   Willem de Bruijn   bpf: pass sk to h...
194
  		skb->sk = sk;
300709849   Daniel Mack   cgroup: add suppo...
195
196
197
  		__skb_push(skb, offset);
  		ret = bpf_prog_run_save_cb(prog, skb) == 1 ? 0 : -EPERM;
  		__skb_pull(skb, offset);
8f917bba0   Willem de Bruijn   bpf: pass sk to h...
198
  		skb->sk = save_sk;
300709849   Daniel Mack   cgroup: add suppo...
199
200
201
202
203
204
  	}
  
  	rcu_read_unlock();
  
  	return ret;
  }
b2cd12574   David Ahern   bpf: Refactor cgr...
205
  EXPORT_SYMBOL(__cgroup_bpf_run_filter_skb);
610236587   David Ahern   bpf: Add new cgro...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  
  /**
   * __cgroup_bpf_run_filter_sk() - Run a program on a sock
   * @sk: sock structure to manipulate
   * @type: The type of program to be exectuted
   *
   * socket is passed is expected to be of type INET or INET6.
   *
   * The program type passed in via @type must be suitable for sock
   * filtering. No further check is performed to assert that.
   *
   * This function will return %-EPERM if any if an attached program was found
   * and if it returned != 1 during execution. In all other cases, 0 is returned.
   */
  int __cgroup_bpf_run_filter_sk(struct sock *sk,
  			       enum bpf_attach_type type)
  {
  	struct cgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
  	struct bpf_prog *prog;
  	int ret = 0;
  
  
  	rcu_read_lock();
  
  	prog = rcu_dereference(cgrp->bpf.effective[type]);
  	if (prog)
  		ret = BPF_PROG_RUN(prog, sk) == 1 ? 0 : -EPERM;
  
  	rcu_read_unlock();
  
  	return ret;
  }
  EXPORT_SYMBOL(__cgroup_bpf_run_filter_sk);
40304b2a1   Lawrence Brakmo   bpf: BPF support ...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  
  /**
   * __cgroup_bpf_run_filter_sock_ops() - Run a program on a sock
   * @sk: socket to get cgroup from
   * @sock_ops: bpf_sock_ops_kern struct to pass to program. Contains
   * sk with connection information (IP addresses, etc.) May not contain
   * cgroup info if it is a req sock.
   * @type: The type of program to be exectuted
   *
   * socket passed is expected to be of type INET or INET6.
   *
   * The program type passed in via @type must be suitable for sock_ops
   * filtering. No further check is performed to assert that.
   *
   * This function will return %-EPERM if any if an attached program was found
   * and if it returned != 1 during execution. In all other cases, 0 is returned.
   */
  int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,
  				     struct bpf_sock_ops_kern *sock_ops,
  				     enum bpf_attach_type type)
  {
  	struct cgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
  	struct bpf_prog *prog;
  	int ret = 0;
  
  
  	rcu_read_lock();
  
  	prog = rcu_dereference(cgrp->bpf.effective[type]);
  	if (prog)
  		ret = BPF_PROG_RUN(prog, sock_ops) == 1 ? 0 : -EPERM;
  
  	rcu_read_unlock();
  
  	return ret;
  }
  EXPORT_SYMBOL(__cgroup_bpf_run_filter_sock_ops);