diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 186 |
1 files changed, 110 insertions, 76 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e81e2fb3d42..69110fed64b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -71,7 +71,7 @@ static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) default: return -EINVAL; - }; + } algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; return 0; @@ -152,7 +152,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, default: goto out; - }; + } err = -EINVAL; switch (p->id.proto) { @@ -192,7 +192,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, default: goto out; - }; + } if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH))) goto out; @@ -217,7 +217,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, default: goto out; - }; + } err = 0; @@ -272,9 +272,8 @@ static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_a } -static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) +static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) { - struct xfrm_sec_ctx *xfrm_ctx = xp->security; int len = 0; if (xfrm_ctx) { @@ -577,7 +576,7 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) struct sk_buff *skb = sp->out_skb; struct xfrm_usersa_info *p; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); if (sp->this_idx < sp->start_idx) goto out; @@ -622,14 +621,14 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) if (x->lastused) RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; out: sp->this_idx++; return 0; nlmsg_failure: rtattr_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -673,6 +672,61 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, return skb; } +static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) +{ + struct xfrm_sadinfo si; + struct nlmsghdr *nlh; + u32 *f; + + nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0); + if (nlh == NULL) /* shouldnt really happen ... */ + return -EMSGSIZE; + + f = nlmsg_data(nlh); + *f = flags; + xfrm_sad_getinfo(&si); + + if (flags & XFRM_SAD_HMASK) + NLA_PUT_U32(skb, XFRMA_SADHMASK, si.sadhcnt); + if (flags & XFRM_SAD_HMAX) + NLA_PUT_U32(skb, XFRMA_SADHMAX, si.sadhmcnt); + if (flags & XFRM_SAD_CNT) + NLA_PUT_U32(skb, XFRMA_SADCNT, si.sadcnt); + + return nlmsg_end(skb, nlh); + +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + +static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, + struct rtattr **xfrma) +{ + struct sk_buff *r_skb; + u32 *flags = NLMSG_DATA(nlh); + u32 spid = NETLINK_CB(skb).pid; + u32 seq = nlh->nlmsg_seq; + int len = NLMSG_LENGTH(sizeof(u32)); + + if (*flags & XFRM_SAD_HMASK) + len += RTA_SPACE(sizeof(u32)); + if (*flags & XFRM_SAD_HMAX) + len += RTA_SPACE(sizeof(u32)); + if (*flags & XFRM_SAD_CNT) + len += RTA_SPACE(sizeof(u32)); + + r_skb = alloc_skb(len, GFP_ATOMIC); + + if (r_skb == NULL) + return -ENOMEM; + + if (build_sadinfo(r_skb, spid, seq, *flags) < 0) + BUG(); + + return nlmsg_unicast(xfrm_nl, r_skb, spid); +} + static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct rtattr **xfrma) { @@ -712,7 +766,7 @@ static int verify_userspi_info(struct xfrm_userspi_info *p) default: return -EINVAL; - }; + } if (p->min > p->max) return -EINVAL; @@ -790,7 +844,7 @@ static int verify_policy_dir(u8 dir) default: return -EINVAL; - }; + } return 0; } @@ -806,7 +860,7 @@ static int verify_policy_type(u8 type) default: return -EINVAL; - }; + } return 0; } @@ -822,7 +876,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) default: return -EINVAL; - }; + } switch (p->action) { case XFRM_POLICY_ALLOW: @@ -831,7 +885,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) default: return -EINVAL; - }; + } switch (p->sel.family) { case AF_INET: @@ -846,7 +900,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) default: return -EINVAL; - }; + } return verify_policy_dir(p->dir); } @@ -913,7 +967,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) #endif default: return -EINVAL; - }; + } } return 0; @@ -1158,7 +1212,7 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr struct sk_buff *in_skb = sp->in_skb; struct sk_buff *skb = sp->out_skb; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); if (sp->this_idx < sp->start_idx) goto out; @@ -1177,13 +1231,13 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr if (copy_to_user_policy_type(xp->type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; out: sp->this_idx++; return 0; nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -1331,7 +1385,7 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve struct xfrm_aevent_id *id; struct nlmsghdr *nlh; struct xfrm_lifetime_cur ltime; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); id = NLMSG_DATA(nlh); @@ -1363,12 +1417,12 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); } - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; rtattr_failure: nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -1745,7 +1799,7 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, struct xfrm_migrate *mp; struct xfrm_userpolicy_id *pol_id; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); int i; nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id)); @@ -1765,10 +1819,10 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, goto nlmsg_failure; } - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -1824,6 +1878,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), + [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)), }; #undef XMSGSIZE @@ -1851,55 +1906,39 @@ static struct xfrm_link { [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, + [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo }, }; -static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) +static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct rtattr *xfrma[XFRMA_MAX]; struct xfrm_link *link; int type, min_len; - if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) - return 0; - type = nlh->nlmsg_type; - - /* A control message: ignore them */ - if (type < XFRM_MSG_BASE) - return 0; - - /* Unknown message: reply with EINVAL */ if (type > XFRM_MSG_MAX) - goto err_einval; + return -EINVAL; type -= XFRM_MSG_BASE; link = &xfrm_dispatch[type]; /* All operations require privileges, even GET */ - if (security_netlink_recv(skb, CAP_NET_ADMIN)) { - *errp = -EPERM; - return -1; - } + if (security_netlink_recv(skb, CAP_NET_ADMIN)) + return -EPERM; if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && (nlh->nlmsg_flags & NLM_F_DUMP)) { if (link->dump == NULL) - goto err_einval; - - if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh, - link->dump, NULL)) != 0) { - return -1; - } + return -EINVAL; - netlink_queue_skip(nlh, skb); - return -1; + return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); } memset(xfrma, 0, sizeof(xfrma)); if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type])) - goto err_einval; + return -EINVAL; if (nlh->nlmsg_len > min_len) { int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); @@ -1909,7 +1948,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err unsigned short flavor = attr->rta_type; if (flavor) { if (flavor > XFRMA_MAX) - goto err_einval; + return -EINVAL; xfrma[flavor - 1] = attr; } attr = RTA_NEXT(attr, attrlen); @@ -1917,14 +1956,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err } if (link->doit == NULL) - goto err_einval; - *errp = link->doit(skb, nlh, xfrma); - - return *errp; + return -EINVAL; -err_einval: - *errp = -EINVAL; - return -1; + return link->doit(skb, nlh, xfrma); } static void xfrm_netlink_rcv(struct sock *sk, int len) @@ -1943,7 +1977,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve { struct xfrm_user_expire *ue; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue)); @@ -1953,11 +1987,11 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve copy_to_user_state(x, &ue->state); ue->hard = (c->data.hard != 0) ? 1 : 0; - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -2000,7 +2034,7 @@ static int xfrm_notify_sa_flush(struct km_event *c) struct xfrm_usersa_flush *p; struct nlmsghdr *nlh; struct sk_buff *skb; - unsigned char *b; + sk_buff_data_t b; int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)); skb = alloc_skb(len, GFP_ATOMIC); @@ -2046,7 +2080,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) struct xfrm_usersa_id *id; struct nlmsghdr *nlh; struct sk_buff *skb; - unsigned char *b; + sk_buff_data_t b; int len = xfrm_sa_len(x); int headlen; @@ -2130,7 +2164,7 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, { struct xfrm_user_acquire *ua; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); __u32 seq = xfrm_get_acqseq(); nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE, @@ -2154,11 +2188,11 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, if (copy_to_user_policy_type(xp->type, skb) < 0) goto nlmsg_failure; - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -2170,7 +2204,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); - len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); + len += RTA_SPACE(xfrm_user_sec_ctx_size(x->security)); #ifdef CONFIG_XFRM_SUB_POLICY len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); #endif @@ -2250,7 +2284,7 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, struct xfrm_user_polexpire *upe; struct nlmsghdr *nlh; int hard = c->data.hard; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); upe = NLMSG_DATA(nlh); @@ -2265,11 +2299,11 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, goto nlmsg_failure; upe->hard = !!hard; - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -2280,7 +2314,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); - len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); + len += RTA_SPACE(xfrm_user_sec_ctx_size(xp->security)); #ifdef CONFIG_XFRM_SUB_POLICY len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); #endif @@ -2301,7 +2335,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * struct xfrm_userpolicy_id *id; struct nlmsghdr *nlh; struct sk_buff *skb; - unsigned char *b; + sk_buff_data_t b; int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); int headlen; @@ -2358,7 +2392,7 @@ static int xfrm_notify_policy_flush(struct km_event *c) { struct nlmsghdr *nlh; struct sk_buff *skb; - unsigned char *b; + sk_buff_data_t b; int len = 0; #ifdef CONFIG_XFRM_SUB_POLICY len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type)); @@ -2411,7 +2445,7 @@ static int build_report(struct sk_buff *skb, u8 proto, { struct xfrm_user_report *ur; struct nlmsghdr *nlh; - unsigned char *b = skb->tail; + unsigned char *b = skb_tail_pointer(skb); nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); ur = NLMSG_DATA(nlh); @@ -2423,12 +2457,12 @@ static int build_report(struct sk_buff *skb, u8 proto, if (addr) RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); - nlh->nlmsg_len = skb->tail - b; + nlh->nlmsg_len = skb_tail_pointer(skb) - b; return skb->len; nlmsg_failure: rtattr_failure: - skb_trim(skb, b - skb->data); + nlmsg_trim(skb, b); return -1; } @@ -2467,7 +2501,7 @@ static int __init xfrm_user_init(void) printk(KERN_INFO "Initializing XFRM netlink socket\n"); nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, - xfrm_netlink_rcv, THIS_MODULE); + xfrm_netlink_rcv, NULL, THIS_MODULE); if (nlsk == NULL) return -ENOMEM; rcu_assign_pointer(xfrm_nl, nlsk); |