lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Mon, 15 Feb 2010 17:46:31 +0100 From: Florian Westphal <fw@...len.de> To: netdev@...r.kernel.org Cc: Florian Westphal <fw@...len.de> Subject: [PATCH 3/5] xfrm: split nlmsg allocation and data copying To support 32bit userland with different u64 alignment requirements than a 64bit kernel (COMPAT_FOR_U64_ALIGNMENT), it is necessary to prepare messages containing affected structures twice: once in the format expected by 64bit listeners, one in the format expected by 32bit applications. In order to minimize copy & pasting and re-use existing code where possible, split nlmsg allocation and data copying. Also, replace foo(..., sizeof(*structure)) with len = sizeof(*structure); foo(..., len); so len can be made conditional if we are preparing a compat message. This will be done in a followup-patch. Signed-off-by: Florian Westphal <fw@...len.de> --- net/xfrm/xfrm_user.c | 156 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 114 insertions(+), 42 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 943c871..bda5c15 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -692,17 +692,16 @@ nla_put_failure: return -EMSGSIZE; } -static int dump_one_state(struct xfrm_state *x, int count, void *ptr) +static int copy_one_state(struct sk_buff *skb, struct xfrm_state *x, struct xfrm_dump_info *sp) { - struct xfrm_dump_info *sp = ptr; struct sk_buff *in_skb = sp->in_skb; - struct sk_buff *skb = sp->out_skb; struct xfrm_usersa_info *p; struct nlmsghdr *nlh; + size_t len = sizeof(*p); int err; nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, - XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); + XFRM_MSG_NEWSA, len, sp->nlmsg_flags); if (nlh == NULL) return -EMSGSIZE; @@ -720,6 +719,14 @@ nla_put_failure: return err; } +static int dump_one_state(struct xfrm_state *x, int count, void *ptr) +{ + struct xfrm_dump_info *sp = ptr; + struct sk_buff *skb = sp->out_skb; + int ret = copy_one_state(skb, x, sp); + return ret; +} + static int xfrm_dump_sa_done(struct netlink_callback *cb) { struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; @@ -1345,16 +1352,15 @@ static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb) } #endif -static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) +static int copy_one_policy(struct sk_buff *skb, struct xfrm_policy *xp, int dir, struct xfrm_dump_info *sp) { - 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 len = sizeof(*p); nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, - XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); + XFRM_MSG_NEWPOLICY, len, sp->nlmsg_flags); if (nlh == NULL) return -EMSGSIZE; @@ -1375,6 +1381,14 @@ nlmsg_failure: return -EMSGSIZE; } +static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) +{ + struct xfrm_dump_info *sp = ptr; + struct sk_buff *skb = sp->out_skb; + int ret = copy_one_policy(skb, xp, dir, sp); + return ret; +} + static int xfrm_dump_policy_done(struct netlink_callback *cb) { struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; @@ -1695,7 +1709,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_user_polexpire *up = nlmsg_data(nlh); struct xfrm_userpolicy_info *p = &up->pol; u8 type = XFRM_POLICY_TYPE_MAIN; - int err = -ENOENT; + int hard, err = -ENOENT; err = copy_from_user_policy_type(&type, attrs); if (err) @@ -1733,7 +1747,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, read_unlock(&xp->lock); err = 0; - if (up->hard) { + hard = up->hard; + if (hard) { uid_t loginuid = NETLINK_CB(skb).loginuid; uid_t sessionid = NETLINK_CB(skb).sessionid; u32 sid = NETLINK_CB(skb).sid; @@ -1744,7 +1759,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, // reset the timers here? printk("Dont know what to do with soft policy expire\n"); } - km_policy_expired(xp, p->dir, up->hard, current->pid); + km_policy_expired(xp, p->dir, hard, current->pid); out: xfrm_pol_put(xp); @@ -1756,7 +1771,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, { struct net *net = sock_net(skb->sk); struct xfrm_state *x; - int err; + int hard, err; struct xfrm_user_expire *ue = nlmsg_data(nlh); struct xfrm_usersa_info *p = &ue->state; @@ -1770,9 +1785,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, err = -EINVAL; if (x->km.state != XFRM_STATE_VALID) goto out; - km_state_expired(x, ue->hard, current->pid); + hard = ue->hard; + km_state_expired(x, hard, current->pid); - if (ue->hard) { + if (hard) { uid_t loginuid = NETLINK_CB(skb).loginuid; uid_t sessionid = NETLINK_CB(skb).sessionid; u32 sid = NETLINK_CB(skb).sid; @@ -2256,26 +2272,35 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) return l; } -static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) +static int xfrm_notify_sa_len(struct xfrm_state *x, const struct km_event *c) { - struct net *net = xs_net(x); - struct xfrm_usersa_info *p; - struct xfrm_usersa_id *id; - struct nlmsghdr *nlh; - struct sk_buff *skb; int len = xfrm_sa_len(x); - int headlen; + int headlen = sizeof(struct xfrm_usersa_info); - headlen = sizeof(*p); if (c->event == XFRM_MSG_DELSA) { len += nla_total_size(headlen); - headlen = sizeof(*id); + headlen = sizeof(struct xfrm_usersa_id); } len += NLMSG_ALIGN(headlen); - skb = nlmsg_new(len, GFP_ATOMIC); - if (skb == NULL) - return -ENOMEM; + return len; +} + +static int xfrm_notify_sa_headlen(const struct km_event *c) +{ + if (c->event == XFRM_MSG_DELSA) + return sizeof(struct xfrm_usersa_id); + return sizeof(struct xfrm_usersa_info); +} + +static int copy_to_user_xfrm_notify_sa(struct sk_buff *skb, + struct xfrm_state *x, struct km_event *c) +{ + struct xfrm_usersa_info *p; + struct xfrm_usersa_id *id; + struct nlmsghdr *nlh; + int sizeof_xfrm_usersa_info = sizeof(*p); + int headlen = xfrm_notify_sa_headlen(c); nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); if (nlh == NULL) @@ -2291,7 +2316,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) id->family = x->props.family; id->proto = x->id.proto; - attr = nla_reserve(skb, XFRMA_SA, sizeof(*p)); + attr = nla_reserve(skb, XFRMA_SA, sizeof_xfrm_usersa_info); if (attr == NULL) goto nla_put_failure; @@ -2302,6 +2327,25 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) goto nla_put_failure; nlmsg_end(skb, nlh); + return 0; +nla_put_failure: + /* Somebody screwed up with xfrm_sa_len! */ + WARN_ON(1); + return -1; +} + +static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) +{ + struct sk_buff *skb; + struct net *net = xs_net(x); + int len = xfrm_notify_sa_len(x, c); + + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (copy_to_user_xfrm_notify_sa(skb, x, c)) + goto nla_put_failure; return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); @@ -2349,10 +2393,11 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, int dir) { struct xfrm_user_acquire *ua; + size_t len = sizeof(*ua); struct nlmsghdr *nlh; __u32 seq = xfrm_get_acqseq(); - nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, len, 0); if (nlh == NULL) return -EMSGSIZE; @@ -2468,10 +2513,11 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, int dir, struct km_event *c) { struct xfrm_user_polexpire *upe; + size_t len = sizeof(*upe); struct nlmsghdr *nlh; int hard = c->data.hard; - nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); + nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, len, 0); if (nlh == NULL) return -EMSGSIZE; @@ -2507,27 +2553,35 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } -static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) +static int xfrm_notify_policy_len(struct xfrm_policy *xp, struct km_event *c) { - struct net *net = xp_net(xp); - struct xfrm_userpolicy_info *p; - struct xfrm_userpolicy_id *id; - struct nlmsghdr *nlh; - struct sk_buff *skb; int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); - int headlen; + int headlen = sizeof(struct xfrm_userpolicy_info); - headlen = sizeof(*p); if (c->event == XFRM_MSG_DELPOLICY) { len += nla_total_size(headlen); - headlen = sizeof(*id); + headlen = sizeof(struct xfrm_userpolicy_id); } len += userpolicy_type_attrsize(); len += NLMSG_ALIGN(headlen); + return len; +} - skb = nlmsg_new(len, GFP_ATOMIC); - if (skb == NULL) - return -ENOMEM; +static int xfrm_notify_policy_headlen(const struct km_event *c) +{ + if (c->event == XFRM_MSG_DELPOLICY) + return sizeof(struct xfrm_userpolicy_id); + return sizeof(struct xfrm_userpolicy_info); +} + +static int copy_to_user_xfrm_notify_policy(struct sk_buff *skb, int dir, + struct xfrm_policy *xp, struct km_event *c) +{ + struct xfrm_userpolicy_info *p; + struct xfrm_userpolicy_id *id; + struct nlmsghdr *nlh; + int sizeof_xfrm_userpolicy_info = sizeof(*p); + int headlen = xfrm_notify_policy_headlen(c); nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); if (nlh == NULL) @@ -2545,7 +2599,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * else memcpy(&id->sel, &xp->selector, sizeof(id->sel)); - attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); + attr = nla_reserve(skb, XFRMA_POLICY, sizeof_xfrm_userpolicy_info); if (attr == NULL) goto nlmsg_failure; @@ -2560,6 +2614,24 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * nlmsg_end(skb, nlh); + return 0; + +nlmsg_failure: + return -1; +} + +static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) +{ + struct net *net = xp_net(xp); + struct sk_buff *skb; + int len = xfrm_notify_policy_len(xp, c); + + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + if (copy_to_user_xfrm_notify_policy(skb, dir, xp, c)) + goto nlmsg_failure; + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: -- 1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists