Messages in this thread Patch in this message | | | From | Dmitry Safonov <> | Subject | [PATCH 12/18] xfrm: Add compat support for xfrm_userpolicy_info messages | Date | Thu, 26 Jul 2018 03:31:38 +0100 |
| |
Parse userpolicy messages sent by userspace according to in_compat_syscall(). Applications that used native bind() syscall are in XFRMNLGRP_POLICY, so send there xfrm_usersa_info messages (with 64-bit ABI). Compatible applications are added to kernel-hidden XFRMNLGRP_COMPAT_POLICY group, so send there xfrm_usersa_info messages_packed (with 32-bit ABI)
Cc: "David S. Miller" <davem@davemloft.net> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Steffen Klassert <steffen.klassert@secunet.com> Cc: netdev@vger.kernel.org Signed-off-by: Dmitry Safonov <dima@arista.com> --- net/xfrm/xfrm_user.c | 73 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 15 deletions(-)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ca1a14f45cf7..df792a3be8f2 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1630,9 +1630,9 @@ static void copy_from_user_policy(struct xfrm_policy *xp, /* XXX xp->share = p->share; */ } -static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) +static void __copy_to_user_policy(struct xfrm_policy *xp, + struct xfrm_userpolicy_info_packed *p, int dir) { - memset(p, 0, sizeof(*p)); memcpy(&p->sel, &xp->selector, sizeof(p->sel)); memcpy(&p->lft, &xp->lft, sizeof(p->lft)); memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); @@ -1645,6 +1645,20 @@ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_i p->share = XFRM_SHARE_ANY; /* XXX xp->share */ } +static void copy_to_user_policy(struct xfrm_policy *xp, + struct xfrm_userpolicy_info *p, int dir) +{ + memset(p, 0, sizeof(*p)); + __copy_to_user_policy(xp, (struct xfrm_userpolicy_info_packed *)p, dir); +} + +static void copy_to_user_policy_compat(struct xfrm_policy *xp, + struct xfrm_userpolicy_info_packed *p, int dir) +{ + memset(p, 0, sizeof(*p)); + __copy_to_user_policy(xp, p, dir); +} + static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info_packed *p, struct nlattr **attrs, int *errp) @@ -1795,19 +1809,26 @@ static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb) static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) { struct xfrm_dump_info *sp = ptr; - struct xfrm_userpolicy_info *p; struct sk_buff *in_skb = sp->in_skb; struct sk_buff *skb = sp->out_skb; struct nlmsghdr *nlh; + size_t msg_len; int err; + if (sp->compat_dump) + msg_len = sizeof(struct xfrm_userpolicy_info_packed); + else + msg_len = sizeof(struct xfrm_userpolicy_info); nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq, - XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); + XFRM_MSG_NEWPOLICY, msg_len, sp->nlmsg_flags); if (nlh == NULL) return -EMSGSIZE; - p = nlmsg_data(nlh); - copy_to_user_policy(xp, p, dir); + if (sp->compat_dump) + copy_to_user_policy_compat(xp, nlmsg_data(nlh), dir); + else + copy_to_user_policy(xp, nlmsg_data(nlh), dir); + err = copy_to_user_tmpl(xp, skb); if (!err) err = copy_to_user_sec_ctx(xp, skb); @@ -1852,6 +1873,7 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; + info.compat_dump = in_compat_syscall(); (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); @@ -1874,6 +1896,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, info.out_skb = skb; info.nlmsg_seq = seq; info.nlmsg_flags = 0; + info.compat_dump = in_compat_syscall(); err = dump_one_policy(xp, dir, 0, &info); if (err) { @@ -3184,18 +3207,24 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); } -static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c) +static int __xfrm_notify_policy(struct xfrm_policy *xp, int dir, + const struct km_event *c, bool compat) { unsigned int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); + unsigned int headlen, upi_size; struct net *net = xp_net(xp); - struct xfrm_userpolicy_info *p; struct xfrm_userpolicy_id *id; + void *userpolicy_info; struct nlmsghdr *nlh; struct sk_buff *skb; - unsigned int headlen; int err; - headlen = sizeof(*p); + if (compat) + upi_size = sizeof(struct xfrm_userpolicy_info_packed); + else + upi_size = sizeof(struct xfrm_userpolicy_info); + headlen = upi_size; + if (c->event == XFRM_MSG_DELPOLICY) { len += nla_total_size(headlen); headlen = sizeof(*id); @@ -3213,7 +3242,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e if (nlh == NULL) goto out_free_skb; - p = nlmsg_data(nlh); + userpolicy_info = nlmsg_data(nlh); if (c->event == XFRM_MSG_DELPOLICY) { struct nlattr *attr; @@ -3225,15 +3254,18 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e else memcpy(&id->sel, &xp->selector, sizeof(id->sel)); - attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); + attr = nla_reserve(skb, XFRMA_POLICY, upi_size); err = -EMSGSIZE; if (attr == NULL) goto out_free_skb; - p = nla_data(attr); + userpolicy_info = nla_data(attr); } - copy_to_user_policy(xp, p, dir); + if (compat) + copy_to_user_policy_compat(xp, userpolicy_info, dir); + else + copy_to_user_policy(xp, userpolicy_info, dir); err = copy_to_user_tmpl(xp, skb); if (!err) err = copy_to_user_policy_type(xp->type, skb); @@ -3244,13 +3276,24 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e nlmsg_end(skb, nlh); - return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); + return xfrm_nlmsg_multicast(net, skb, 0, compat ? + XFRMNLGRP_COMPAT_POLICY : XFRMNLGRP_POLICY); out_free_skb: kfree_skb(skb); return err; } +static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, + const struct km_event *c) +{ + int ret = __xfrm_notify_policy(xp, dir, c, false); + + if ((ret && ret != -ESRCH) || !IS_ENABLED(CONFIG_COMPAT)) + return ret; + return __xfrm_notify_policy(xp, dir, c, true); +} + static int xfrm_notify_policy_flush(const struct km_event *c) { struct net *net = c->net; -- 2.13.6
| |