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