From: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> Date: Fri, 15 Mar 2024 12:37:29 +0100 > Use the new added capable_any function in appropriate cases, where a > task is required to have any of two capabilities. > > Add sock_ns_capable_any() wrapper similar to existing sock_ns_capable() > one. > > Reorder CAP_SYS_ADMIN last. > > Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> > Reviewed-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx> (ieee802154 portion) > --- > v4: > - introduce sockopt_ns_capable_any() > v3: > - rename to capable_any() > - make use of ns_capable_any > --- > include/net/sock.h | 1 + > net/caif/caif_socket.c | 2 +- > net/core/sock.c | 15 +++++++++------ > net/ieee802154/socket.c | 6 ++---- > net/ipv4/ip_sockglue.c | 5 +++-- > net/ipv6/ipv6_sockglue.c | 3 +-- > net/unix/af_unix.c | 2 +- > 7 files changed, 18 insertions(+), 16 deletions(-) > > diff --git a/include/net/sock.h b/include/net/sock.h > index b5e00702acc1..2e64a80c8fca 100644 > --- a/include/net/sock.h > +++ b/include/net/sock.h > @@ -1736,6 +1736,7 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow) > void sockopt_lock_sock(struct sock *sk); > void sockopt_release_sock(struct sock *sk); > bool sockopt_ns_capable(struct user_namespace *ns, int cap); > +bool sockopt_ns_capable_any(struct user_namespace *ns, int cap1, int cap2); > bool sockopt_capable(int cap); > > /* Used by processes to "lock" a socket state, so that > diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c > index 039dfbd367c9..2d811037e378 100644 > --- a/net/caif/caif_socket.c > +++ b/net/caif/caif_socket.c > @@ -1026,7 +1026,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, > .usersize = sizeof_field(struct caifsock, conn_req.param) > }; > > - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_NET_ADMIN)) > + if (!capable_any(CAP_NET_ADMIN, CAP_SYS_ADMIN)) > return -EPERM; > /* > * The sock->type specifies the socket type to use. > diff --git a/net/core/sock.c b/net/core/sock.c > index 43bf3818c19e..fa9edcc3e23d 100644 > --- a/net/core/sock.c > +++ b/net/core/sock.c > @@ -1077,6 +1077,12 @@ bool sockopt_ns_capable(struct user_namespace *ns, int cap) > } > EXPORT_SYMBOL(sockopt_ns_capable); > > +bool sockopt_ns_capable_any(struct user_namespace *ns, int cap1, int cap2) > +{ > + return has_current_bpf_ctx() || ns_capable_any(ns, cap1, cap2); > +} > +EXPORT_SYMBOL(sockopt_ns_capable_any); > + > bool sockopt_capable(int cap) > { > return has_current_bpf_ctx() || capable(cap); > @@ -1118,8 +1124,7 @@ int sk_setsockopt(struct sock *sk, int level, int optname, > switch (optname) { > case SO_PRIORITY: > if ((val >= 0 && val <= 6) || > - sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) || > - sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { > + sockopt_ns_capable_any(sock_net(sk)->user_ns, CAP_NET_RAW, CAP_NET_ADMIN)) { > sock_set_priority(sk, val); > return 0; > } > @@ -1422,8 +1427,7 @@ int sk_setsockopt(struct sock *sk, int level, int optname, > break; > > case SO_MARK: > - if (!sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) && > - !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { > + if (!sockopt_ns_capable_any(sock_net(sk)->user_ns, CAP_NET_RAW, CAP_NET_ADMIN)) { > ret = -EPERM; > break; > } > @@ -2813,8 +2817,7 @@ int __sock_cmsg_send(struct sock *sk, struct cmsghdr *cmsg, > > switch (cmsg->cmsg_type) { > case SO_MARK: > - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) && > - !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) > + if (!ns_capable_any(sock_net(sk)->user_ns, CAP_NET_RAW, CAP_NET_ADMIN)) > return -EPERM; > if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32))) > return -EINVAL; > diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c > index 990a83455dcf..42b3b12eb493 100644 > --- a/net/ieee802154/socket.c > +++ b/net/ieee802154/socket.c > @@ -902,8 +902,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname, > ro->want_lqi = !!val; > break; > case WPAN_SECURITY: > - if (!ns_capable(net->user_ns, CAP_NET_ADMIN) && > - !ns_capable(net->user_ns, CAP_NET_RAW)) { > + if (!ns_capable_any(net->user_ns, CAP_NET_ADMIN, CAP_NET_RAW)) { IIUC, should CAP_NET_RAW be tested first ? Then, perhaps you should remove the Reviewed-by tag. > err = -EPERM; > break; > } > @@ -926,8 +925,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname, > } > break; > case WPAN_SECURITY_LEVEL: > - if (!ns_capable(net->user_ns, CAP_NET_ADMIN) && > - !ns_capable(net->user_ns, CAP_NET_RAW)) { > + if (!ns_capable_any(net->user_ns, CAP_NET_ADMIN, CAP_NET_RAW)) { Same here. Thanks! > err = -EPERM; > break; > } > diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c > index cf377377b52d..5a1e5ee20ddd 100644 > --- a/net/ipv4/ip_sockglue.c > +++ b/net/ipv4/ip_sockglue.c > @@ -1008,8 +1008,9 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, > inet_assign_bit(MC_ALL, sk, val); > return 0; > case IP_TRANSPARENT: > - if (!!val && !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) && > - !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) > + if (!!val && > + !sockopt_ns_capable_any(sock_net(sk)->user_ns, > + CAP_NET_RAW, CAP_NET_ADMIN)) > return -EPERM; > if (optlen < 1) > return -EINVAL; > diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c > index d4c28ec1bc51..e46b11b5d3dd 100644 > --- a/net/ipv6/ipv6_sockglue.c > +++ b/net/ipv6/ipv6_sockglue.c > @@ -773,8 +773,7 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, > break; > > case IPV6_TRANSPARENT: > - if (valbool && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW) && > - !sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN)) { > + if (valbool && !sockopt_ns_capable_any(net->user_ns, CAP_NET_RAW, CAP_NET_ADMIN)) { > retv = -EPERM; > break; > } > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c > index 5b41e2321209..acc36b2d25d7 100644 > --- a/net/unix/af_unix.c > +++ b/net/unix/af_unix.c > @@ -1783,7 +1783,7 @@ static inline bool too_many_unix_fds(struct task_struct *p) > struct user_struct *user = current_user(); > > if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) > - return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); > + return !capable_any(CAP_SYS_RESOURCE, CAP_SYS_ADMIN); > return false; > } > > -- > 2.43.0