Some socket options affect how the network namespace treats packets, not just the socket, and require a capability. Convert their checks. These accept CAP_NET_ADMIN or CAP_NET_RAW today, and now accept NET_RIGHT_SOCKOPT or NET_RIGHT_RAW: SO_MARK, both as an option and as a control message, SO_PRIORITY outside of the unprivileged range, IP_TRANSPARENT and IPV6_TRANSPARENT. This one requires CAP_NET_ADMIN, and now NET_RIGHT_SOCKOPT: SO_TXTIME with a clock other than CLOCK_MONOTONIC. These require CAP_NET_RAW, and now NET_RIGHT_RAW: SO_BINDTODEVICE on a socket that is already bound to a device, and the IPv6 hop-by-hop and destination options. Not converted: IP_IPSEC_POLICY, IP_XFRM_POLICY and their IPv6 counterparts, and SO_ATTACH_FILTER on a TCP socket. No functional change. Signed-off-by: Josef Bacik --- net/core/sock.c | 16 ++++++++-------- net/ipv4/ip_sockglue.c | 4 ++-- net/ipv6/ipv6_sockglue.c | 7 +++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 352310066e35..ba870aa6b967 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -462,8 +462,8 @@ static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, static bool sk_set_prio_allowed(const struct sock *sk, int val) { return ((val >= TC_PRIO_BESTEFFORT && val <= TC_PRIO_INTERACTIVE) || - sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) || - sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)); + sockopt_net_may(sk, NET_RIGHT_RAW) || + sockopt_net_may(sk, NET_RIGHT_SOCKOPT)); } static bool sock_needs_netstamp(const struct sock *sk) @@ -642,7 +642,7 @@ static int sock_bindtoindex_locked(struct sock *sk, int ifindex) /* Sorry... */ ret = -EPERM; - if (sk->sk_bound_dev_if && !ns_capable(net->user_ns, CAP_NET_RAW)) + if (sk->sk_bound_dev_if && !net_may(net, NET_RIGHT_RAW)) goto out; ret = -EINVAL; @@ -1540,8 +1540,8 @@ 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_net_may(sk, NET_RIGHT_RAW) && + !sockopt_net_may(sk, NET_RIGHT_SOCKOPT)) { ret = -EPERM; break; } @@ -1649,7 +1649,7 @@ int sk_setsockopt(struct sock *sk, int level, int optname, * scheduler has enough safe guards. */ if (sk_txtime.clockid != CLOCK_MONOTONIC && - !sockopt_ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { + !sockopt_net_may(sk, NET_RIGHT_SOCKOPT)) { ret = -EPERM; break; } @@ -3172,8 +3172,8 @@ 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 (!net_may(sock_net(sk), NET_RIGHT_RAW) && + !net_may(sock_net(sk), NET_RIGHT_SOCKOPT)) return -EPERM; if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32))) return -EINVAL; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index e06c1f48ecad..cc9e0bc952f2 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1008,8 +1008,8 @@ 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_net_may(sk, NET_RIGHT_RAW) && + !sockopt_net_may(sk, NET_RIGHT_SOCKOPT)) return -EPERM; if (optlen < 1) return -EINVAL; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4b3536571c98..d2880493d33b 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -304,12 +304,11 @@ static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval, { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_opt_hdr *new = NULL; - struct net *net = sock_net(sk); struct ipv6_txoptions *opt; int err; /* hop-by-hop / destination options are privileged option */ - if (optname != IPV6_RTHDR && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW)) + if (optname != IPV6_RTHDR && !sockopt_net_may(sk, NET_RIGHT_RAW)) return -EPERM; /* remove any sticky options header with a zero option @@ -405,8 +404,8 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname, inet_assign_bit(FREEBIND, sk, valbool); return 0; 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_net_may(sk, NET_RIGHT_RAW) && + !sockopt_net_may(sk, NET_RIGHT_SOCKOPT)) return -EPERM; if (optlen < sizeof(int)) return -EINVAL; -- 2.55.0