diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 75 | 
1 files changed, 70 insertions, 5 deletions
| diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 894cda0206bb..81dca96d2be6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1360,7 +1360,72 @@ retry:  	return err;  } -static inline int netlink_capable(const struct socket *sock, unsigned int flag) +/** + * __netlink_ns_capable - General netlink message capability test + * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace. + * @user_ns: The user namespace of the capability to use + * @cap: The capability to use + * + * Test to see if the opener of the socket we received the message + * from had when the netlink socket was created and the sender of the + * message has has the capability @cap in the user namespace @user_ns. + */ +bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, +			struct user_namespace *user_ns, int cap) +{ +	return sk_ns_capable(nsp->sk, user_ns, cap); +} +EXPORT_SYMBOL(__netlink_ns_capable); + +/** + * netlink_ns_capable - General netlink message capability test + * @skb: socket buffer holding a netlink command from userspace + * @user_ns: The user namespace of the capability to use + * @cap: The capability to use + * + * Test to see if the opener of the socket we received the message + * from had when the netlink socket was created and the sender of the + * message has has the capability @cap in the user namespace @user_ns. + */ +bool netlink_ns_capable(const struct sk_buff *skb, +			struct user_namespace *user_ns, int cap) +{ +	return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap); +} +EXPORT_SYMBOL(netlink_ns_capable); + +/** + * netlink_capable - Netlink global message capability test + * @skb: socket buffer holding a netlink command from userspace + * @cap: The capability to use + * + * Test to see if the opener of the socket we received the message + * from had when the netlink socket was created and the sender of the + * message has has the capability @cap in all user namespaces. + */ +bool netlink_capable(const struct sk_buff *skb, int cap) +{ +	return netlink_ns_capable(skb, &init_user_ns, cap); +} +EXPORT_SYMBOL(netlink_capable); + +/** + * netlink_net_capable - Netlink network namespace message capability test + * @skb: socket buffer holding a netlink command from userspace + * @cap: The capability to use + * + * Test to see if the opener of the socket we received the message + * from had when the netlink socket was created and the sender of the + * message has has the capability @cap over the network namespace of + * the socket we received the message from. + */ +bool netlink_net_capable(const struct sk_buff *skb, int cap) +{ +	return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap); +} +EXPORT_SYMBOL(netlink_net_capable); + +static inline int netlink_allowed(const struct socket *sock, unsigned int flag)  {  	return (nl_table[sock->sk->sk_protocol].flags & flag) ||  		ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); @@ -1428,7 +1493,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,  	/* Only superuser is allowed to listen multicasts */  	if (nladdr->nl_groups) { -		if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) +		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))  			return -EPERM;  		err = netlink_realloc_groups(sk);  		if (err) @@ -1490,7 +1555,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,  		return -EINVAL;  	if ((nladdr->nl_groups || nladdr->nl_pid) && -	    !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) +	    !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))  		return -EPERM;  	if (!nlk->portid) @@ -2096,7 +2161,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,  		break;  	case NETLINK_ADD_MEMBERSHIP:  	case NETLINK_DROP_MEMBERSHIP: { -		if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) +		if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))  			return -EPERM;  		err = netlink_realloc_groups(sk);  		if (err) @@ -2247,7 +2312,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,  		dst_group = ffs(addr->nl_groups);  		err =  -EPERM;  		if ((dst_group || dst_portid) && -		    !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) +		    !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))  			goto out;  	} else {  		dst_portid = nlk->dst_portid; | 

