|
@@ -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;
|