Using BPF_PROG_DETACH on a flow dissector program supports neither attach_flags nor attach_bpf_fd. Yet no value is enforced for them. Enforce that attach_flags are zero, and require the current program to be passed via attach_bpf_fd. This allows us to remove the check for CAP_SYS_ADMIN, since userspace can now no longer remove arbitrary flow dissector programs.
Unified · Split
| @@ -33,7 +33,7 @@ int netns_bpf_prog_query(const union bpf_attr *attr, · 32 unmodified lines | ||
| 33 | 33 | union bpf_attr __user *uattr); |
| 34 | 34 | int netns_bpf_prog_attach(const union bpf_attr *attr, |
| 35 | 35 | struct bpf_prog *prog); |
| 36 | −int netns_bpf_prog_detach(const union bpf_attr *attr); | |
| 36 | +int netns_bpf_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype); | |
| 37 | 37 | int netns_bpf_link_create(const union bpf_attr *attr, |
| 38 | 38 | struct bpf_prog *prog); |
| 39 | 39 | #else |
| @@ -49,7 +49,8 @@ static inline int netns_bpf_prog_attach(const union bpf_attr *attr, · 9 unmodified lines | ||
| 49 | 49 | return -EOPNOTSUPP; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | −static inline int netns_bpf_prog_detach(const union bpf_attr *attr) | |
| 52 | +static inline int netns_bpf_prog_detach(const union bpf_attr *attr, | |
| 53 | + enum bpf_prog_type ptype) | |
| 53 | 54 | { |
| 54 | 55 | return -EOPNOTSUPP; |
| 55 | 56 | } |
| @@ -269,7 +269,8 @@ out_unlock: · 268 unmodified lines | ||
| 269 | 269 | |
| 270 | 270 | /* Must be called with netns_bpf_mutex held. */ |
| 271 | 271 | static int __netns_bpf_prog_detach(struct net *net, |
| 272 | − enum netns_bpf_attach_type type) | |
| 272 | + enum netns_bpf_attach_type type, | |
| 273 | + struct bpf_prog *old) | |
| 273 | 274 | { |
| 274 | 275 | struct bpf_prog *attached; |
| 275 | 276 | |
| @@ -278,7 +279,7 @@ static int __netns_bpf_prog_detach(struct net *net, · 2 unmodified lines | ||
| 278 | 279 | return -EINVAL; |
| 279 | 280 | |
| 280 | 281 | attached = net->bpf.progs[type]; |
| 281 | − if (!attached) | |
| 282 | + if (!attached || attached != old) | |
| 282 | 283 | return -ENOENT; |
| 283 | 284 | netns_bpf_run_array_detach(net, type); |
| 284 | 285 | net->bpf.progs[type] = NULL; |
| @@ -286,19 +287,29 @@ static int __netns_bpf_prog_detach(struct net *net, · 1 unmodified line | ||
| 286 | 287 | return 0; |
| 287 | 288 | } |
| 288 | 289 | |
| 289 | −int netns_bpf_prog_detach(const union bpf_attr *attr) | |
| 290 | +int netns_bpf_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype) | |
| 290 | 291 | { |
| 291 | 292 | enum netns_bpf_attach_type type; |
| 293 | + struct bpf_prog *prog; | |
| 292 | 294 | int ret; |
| 293 | 295 | |
| 296 | + if (attr->target_fd) | |
| 297 | + return -EINVAL; | |
| 298 | + | |
| 294 | 299 | type = to_netns_bpf_attach_type(attr->attach_type); |
| 295 | 300 | if (type < 0) |
| 296 | 301 | return -EINVAL; |
| 297 | 302 | |
| 303 | + prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype); | |
| 304 | + if (IS_ERR(prog)) | |
| 305 | + return PTR_ERR(prog); | |
| 306 | + | |
| 298 | 307 | mutex_lock(&netns_bpf_mutex); |
| 299 | − ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type); | |
| 308 | + ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type, prog); | |
| 300 | 309 | mutex_unlock(&netns_bpf_mutex); |
| 301 | 310 | |
| 311 | + bpf_prog_put(prog); | |
| 312 | + | |
| 302 | 313 | return ret; |
| 303 | 314 | } |
| 304 | 315 | |
| @@ -2897,9 +2897,7 @@ static int bpf_prog_detach(const union bpf_attr *attr) · 2896 unmodified lines | ||
| 2897 | 2897 | case BPF_PROG_TYPE_LIRC_MODE2: |
| 2898 | 2898 | return lirc_prog_detach(attr); |
| 2899 | 2899 | case BPF_PROG_TYPE_FLOW_DISSECTOR: |
| 2900 | − if (!capable(CAP_NET_ADMIN)) | |
| 2901 | − return -EPERM; | |
| 2902 | − return netns_bpf_prog_detach(attr); | |
| 2900 | + return netns_bpf_prog_detach(attr, ptype); | |
| 2903 | 2901 | case BPF_PROG_TYPE_CGROUP_DEVICE: |
| 2904 | 2902 | case BPF_PROG_TYPE_CGROUP_SKB: |
| 2905 | 2903 | case BPF_PROG_TYPE_CGROUP_SOCK: |