From: Andrey Vagin <ava...@openvz.org>

This patch adds an repair mode for netlink sockets. sendmsg queues
messages into a receive queue if a socket is in the repair mode.

https://jira.sw.ru/browse/PSBM-28386

Signed-off-by: Andrey Vagin <ava...@virtuozzo.com>
Reviewed-by: Cyrill Gorcunov <gorcu...@virtuozzo.com>

https://jira.sw.ru/browse/PSBM-101289
vz7 commit: 2f8d39b73cfca ("netlink: add an ability to restore messages in a
receive queue")

Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com>

+++
netlink: protect NETLINK_REPAIR

Prevent using netlink repair mode from containers.

Signed-off-by: Andrey Zhadchenko <andrey.zhadche...@virtuozzo.com>
Signed-off-by: Cyrill Gorcunov <gorcu...@virtuozzo.com>
---
 include/uapi/linux/netlink.h |  1 +
 net/netlink/af_netlink.c     | 56 ++++++++++++++++++++++++++----------
 net/netlink/af_netlink.h     |  2 ++
 3 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 4c0cde075c27..cdab1c041913 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -159,6 +159,7 @@ enum nlmsgerr_attrs {
 #define NETLINK_CAP_ACK                        10
 #define NETLINK_EXT_ACK                        11
 #define NETLINK_GET_STRICT_CHK         12
+#define NETLINK_REPAIR                 127
 
 struct nl_pktinfo {
        __u32   group;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 6042bbc8c560..7eadbb5f01c4 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1343,6 +1343,7 @@ static int netlink_unicast_kernel(struct sock *sk, struct 
sk_buff *skb,
 int netlink_unicast(struct sock *ssk, struct sk_buff *skb,
                    u32 portid, int nonblock)
 {
+       struct netlink_sock *nlk = nlk_sk(ssk);
        struct sock *sk;
        int err;
        long timeo;
@@ -1351,19 +1352,24 @@ int netlink_unicast(struct sock *ssk, struct sk_buff 
*skb,
 
        timeo = sock_sndtimeo(ssk, nonblock);
 retry:
-       sk = netlink_getsockbyportid(ssk, portid);
-       if (IS_ERR(sk)) {
-               kfree_skb(skb);
-               return PTR_ERR(sk);
-       }
-       if (netlink_is_kernel(sk))
-               return netlink_unicast_kernel(sk, skb, ssk);
+       if (nlk->flags & NETLINK_F_REPAIR) {
+               sk = ssk;
+               sock_hold(sk);
+       } else {
+               sk = netlink_getsockbyportid(ssk, portid);
+               if (IS_ERR(sk)) {
+                       kfree_skb(skb);
+                       return PTR_ERR(sk);
+               }
+               if (netlink_is_kernel(sk))
+                       return netlink_unicast_kernel(sk, skb, ssk);
 
-       if (sk_filter(sk, skb)) {
-               err = skb->len;
-               kfree_skb(skb);
-               sock_put(sk);
-               return err;
+               if (sk_filter(sk, skb)) {
+                       err = skb->len;
+                       kfree_skb(skb);
+                       sock_put(sk);
+                       return err;
+               }
        }
 
        err = netlink_attachskb(sk, skb, &timeo, ssk);
@@ -1666,6 +1672,20 @@ static int netlink_setsockopt(struct socket *sock, int 
level, int optname,
                return -EFAULT;
 
        switch (optname) {
+       case NETLINK_REPAIR:
+#ifdef CONFIG_VE
+               {
+                       struct ve_struct *ve = get_exec_env();
+                       if (!ve_is_super(ve) && !ve->is_pseudosuper)
+                               return -ENOPROTOOPT;
+               }
+#endif
+               if (val)
+                       nlk->flags |= NETLINK_F_REPAIR;
+               else
+                       nlk->flags &= ~NETLINK_F_REPAIR;
+               err = 0;
+               break;
        case NETLINK_PKTINFO:
                if (val)
                        nlk->flags |= NETLINK_F_RECV_PKTINFO;
@@ -1882,6 +1902,7 @@ static int netlink_sendmsg(struct socket *sock, struct 
msghdr *msg, size_t len)
        int err;
        struct scm_cookie scm;
        u32 netlink_skb_flags = 0;
+       bool repair = nlk->flags & NETLINK_F_REPAIR;
 
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
@@ -1900,7 +1921,8 @@ static int netlink_sendmsg(struct socket *sock, struct 
msghdr *msg, size_t len)
                dst_group = ffs(addr->nl_groups);
                err =  -EPERM;
                if ((dst_group || dst_portid) &&
-                   !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
+                   !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND &&
+                   !repair))
                        goto out;
                netlink_skb_flags |= NETLINK_SKB_DST;
        } else {
@@ -1925,7 +1947,11 @@ static int netlink_sendmsg(struct socket *sock, struct 
msghdr *msg, size_t len)
        if (skb == NULL)
                goto out;
 
-       NETLINK_CB(skb).portid  = nlk->portid;
+       if (unlikely(repair))
+               NETLINK_CB(skb).portid = dst_portid;
+       else
+               NETLINK_CB(skb).portid  = nlk->portid;
+
        NETLINK_CB(skb).dst_group = dst_group;
        NETLINK_CB(skb).creds   = scm.creds;
        NETLINK_CB(skb).flags   = netlink_skb_flags;
@@ -1942,7 +1968,7 @@ static int netlink_sendmsg(struct socket *sock, struct 
msghdr *msg, size_t len)
                goto out;
        }
 
-       if (dst_group) {
+       if (dst_group && !repair) {
                refcount_inc(&skb->users);
                netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL);
        }
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index 5f454c8de6a4..7e82297fdd8c 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -17,6 +17,8 @@
 #define NETLINK_F_EXT_ACK              0x40
 #define NETLINK_F_STRICT_CHK           0x80
 
+#define NETLINK_F_REPAIR               0x80000000
+
 #define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
 #define NLGRPLONGS(x)  (NLGRPSZ(x)/sizeof(unsigned long))
 
-- 
2.31.1

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to