Loading...
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 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 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 | /* * 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); cgrp->bpf.disallow_override[type] = parent->bpf.disallow_override[type]; } } /** * __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. * * 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 * 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. */ int __cgroup_bpf_update(struct cgroup *cgrp, struct cgroup *parent, struct bpf_prog *prog, enum bpf_attach_type type, bool new_overridable) { struct bpf_prog *old_prog, *effective = NULL; struct cgroup_subsys_state *pos; bool overridable = true; 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; } if (!prog && !old_prog) /* report error when trying to detach and nothing is attached */ return -ENOENT; cgrp->bpf.prog[type] = prog; 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 */ if (desc->bpf.prog[type] && desc != cgrp) { pos = css_rightmost_descendant(pos); } else { rcu_assign_pointer(desc->bpf.effective[type], effective); desc->bpf.disallow_override[type] = !overridable; } } if (prog) static_branch_inc(&cgroup_bpf_enabled_key); if (old_prog) { bpf_prog_put(old_prog); static_branch_dec(&cgroup_bpf_enabled_key); } return 0; } /** * __cgroup_bpf_run_filter_skb() - Run a program for packet filtering * @sk: The socket sending or receiving traffic * @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. */ int __cgroup_bpf_run_filter_skb(struct sock *sk, struct sk_buff *skb, enum bpf_attach_type type) { 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); struct sock *save_sk = skb->sk; skb->sk = sk; __skb_push(skb, offset); ret = bpf_prog_run_save_cb(prog, skb) == 1 ? 0 : -EPERM; __skb_pull(skb, offset); skb->sk = save_sk; } rcu_read_unlock(); return ret; } EXPORT_SYMBOL(__cgroup_bpf_run_filter_skb); /** * __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); /** * __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); |