X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fxfrm%2Fxfrm_user.c;h=7de17559249a28e30f25dbd21a0ff1d408060661;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=81d1005830f4d23d88ba4b06c4932fef1f060345;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 81d100583..7de175592 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -28,6 +28,8 @@ #include #include +static struct sock *xfrm_nl; + static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) { struct rtattr *rt = xfrma[type - 1]; @@ -101,6 +103,9 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma) uctx = RTA_DATA(rt); + if (uctx->ctx_len > PAGE_SIZE) + return -EINVAL; + len += sizeof(struct xfrm_user_sec_ctx); len += uctx->ctx_len; @@ -271,56 +276,6 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * x->props.flags = p->flags; } -/* - * someday when pfkey also has support, we could have the code - * somehow made shareable and move it to xfrm_state.c - JHS - * -*/ -static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) -{ - int err = - EINVAL; - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; - struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; - struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; - - if (rp) { - struct xfrm_replay_state *replay; - if (RTA_PAYLOAD(rp) < sizeof(*replay)) - goto error; - replay = RTA_DATA(rp); - memcpy(&x->replay, replay, sizeof(*replay)); - memcpy(&x->preplay, replay, sizeof(*replay)); - } - - if (lt) { - struct xfrm_lifetime_cur *ltime; - if (RTA_PAYLOAD(lt) < sizeof(*ltime)) - goto error; - ltime = RTA_DATA(lt); - x->curlft.bytes = ltime->bytes; - x->curlft.packets = ltime->packets; - x->curlft.add_time = ltime->add_time; - x->curlft.use_time = ltime->use_time; - } - - if (et) { - if (RTA_PAYLOAD(et) < sizeof(u32)) - goto error; - x->replay_maxage = *(u32*)RTA_DATA(et); - } - - if (rt) { - if (RTA_PAYLOAD(rt) < sizeof(u32)) - goto error; - x->replay_maxdiff = *(u32*)RTA_DATA(rt); - } - - return 0; -error: - return err; -} - static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, struct rtattr **xfrma, int *errp) @@ -356,18 +311,6 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, goto error; x->km.seq = p->seq; - x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; - /* sysctl_xfrm_aevent_etime is in 100ms units */ - x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; - x->preplay.bitmap = 0; - x->preplay.seq = x->replay.seq+x->replay_maxdiff; - x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; - - /* override default values from above */ - - err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); - if (err < 0) - goto error; return x; @@ -1082,142 +1025,9 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma return 0; } - -static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) -{ - struct xfrm_aevent_id *id; - struct nlmsghdr *nlh; - struct xfrm_lifetime_cur ltime; - unsigned char *b = skb->tail; - - nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); - id = NLMSG_DATA(nlh); - nlh->nlmsg_flags = 0; - - id->sa_id.daddr = x->id.daddr; - id->sa_id.spi = x->id.spi; - id->sa_id.family = x->props.family; - id->sa_id.proto = x->id.proto; - id->flags = c->data.aevent; - - RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); - - ltime.bytes = x->curlft.bytes; - ltime.packets = x->curlft.packets; - ltime.add_time = x->curlft.add_time; - ltime.use_time = x->curlft.use_time; - - RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); - - if (id->flags&XFRM_AE_RTHR) { - RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); - } - - if (id->flags&XFRM_AE_ETHR) { - u32 etimer = x->replay_maxage*10/HZ; - RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); - } - - nlh->nlmsg_len = skb->tail - b; - return skb->len; - -rtattr_failure: -nlmsg_failure: - skb_trim(skb, b - skb->data); - return -1; -} - -static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_state *x; - struct sk_buff *r_skb; - int err; - struct km_event c; - struct xfrm_aevent_id *p = NLMSG_DATA(nlh); - int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); - struct xfrm_usersa_id *id = &p->sa_id; - - len += RTA_SPACE(sizeof(struct xfrm_replay_state)); - len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); - - if (p->flags&XFRM_AE_RTHR) - len+=RTA_SPACE(sizeof(u32)); - - if (p->flags&XFRM_AE_ETHR) - len+=RTA_SPACE(sizeof(u32)); - - r_skb = alloc_skb(len, GFP_ATOMIC); - if (r_skb == NULL) - return -ENOMEM; - - x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); - if (x == NULL) { - kfree(r_skb); - return -ESRCH; - } - - /* - * XXX: is this lock really needed - none of the other - * gets lock (the concern is things getting updated - * while we are still reading) - jhs - */ - spin_lock_bh(&x->lock); - c.data.aevent = p->flags; - c.seq = nlh->nlmsg_seq; - c.pid = nlh->nlmsg_pid; - - if (build_aevent(r_skb, x, &c) < 0) - BUG(); - err = netlink_unicast(xfrm_nl, r_skb, - NETLINK_CB(skb).pid, MSG_DONTWAIT); - spin_unlock_bh(&x->lock); - xfrm_state_put(x); - return err; -} - -static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_state *x; - struct km_event c; - int err = - EINVAL; - struct xfrm_aevent_id *p = NLMSG_DATA(nlh); - struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; - struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; - - if (!lt && !rp) - return err; - - /* pedantic mode - thou shalt sayeth replaceth */ - if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) - return err; - - x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); - if (x == NULL) - return -ESRCH; - - if (x->km.state != XFRM_STATE_VALID) - goto out; - - spin_lock_bh(&x->lock); - err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); - spin_unlock_bh(&x->lock); - if (err < 0) - goto out; - - c.event = nlh->nlmsg_type; - c.seq = nlh->nlmsg_seq; - c.pid = nlh->nlmsg_pid; - c.data.aevent = XFRM_AE_CU; - km_state_notify(x, &c); - err = 0; -out: - xfrm_state_put(x); - return err; -} - static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) { -struct km_event c; + struct km_event c; xfrm_policy_flush(); c.event = nlh->nlmsg_type; @@ -1227,139 +1037,6 @@ struct km_event c; return 0; } -static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_policy *xp; - struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); - struct xfrm_userpolicy_info *p = &up->pol; - int err = -ENOENT; - - if (p->index) - xp = xfrm_policy_byid(p->dir, p->index, 0); - else { - struct rtattr **rtattrs = (struct rtattr **)xfrma; - struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; - struct xfrm_policy tmp; - - err = verify_sec_ctx_len(rtattrs); - if (err) - return err; - - memset(&tmp, 0, sizeof(struct xfrm_policy)); - if (rt) { - struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); - - if ((err = security_xfrm_policy_alloc(&tmp, uctx))) - return err; - } - xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); - security_xfrm_policy_free(&tmp); - } - - if (xp == NULL) - return err; - read_lock(&xp->lock); - if (xp->dead) { - read_unlock(&xp->lock); - goto out; - } - - read_unlock(&xp->lock); - err = 0; - if (up->hard) { - xfrm_policy_delete(xp, p->dir); - } else { - // 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); - -out: - xfrm_pol_put(xp); - return err; -} - -static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_state *x; - int err; - struct xfrm_user_expire *ue = NLMSG_DATA(nlh); - struct xfrm_usersa_info *p = &ue->state; - - x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); - err = -ENOENT; - - if (x == NULL) - return err; - - err = -EINVAL; - - spin_lock_bh(&x->lock); - if (x->km.state != XFRM_STATE_VALID) - goto out; - km_state_expired(x, ue->hard, current->pid); - - if (ue->hard) - __xfrm_state_delete(x); -out: - spin_unlock_bh(&x->lock); - xfrm_state_put(x); - return err; -} - -static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_policy *xp; - struct xfrm_user_tmpl *ut; - int i; - struct rtattr *rt = xfrma[XFRMA_TMPL-1]; - - struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); - struct xfrm_state *x = xfrm_state_alloc(); - int err = -ENOMEM; - - if (!x) - return err; - - err = verify_newpolicy_info(&ua->policy); - if (err) { - printk("BAD policy passed\n"); - kfree(x); - return err; - } - - /* build an XP */ - xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { - kfree(x); - return err; - } - - memcpy(&x->id, &ua->id, sizeof(ua->id)); - memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); - memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); - - ut = RTA_DATA(rt); - /* extract the templates and for each call km_key */ - for (i = 0; i < xp->xfrm_nr; i++, ut++) { - struct xfrm_tmpl *t = &xp->xfrm_vec[i]; - memcpy(&x->id, &t->id, sizeof(x->id)); - x->props.mode = t->mode; - x->props.reqid = t->reqid; - x->props.family = ut->family; - t->aalgos = ua->aalgos; - t->ealgos = ua->ealgos; - t->calgos = ua->calgos; - err = km_query(x, t, xp); - - } - - kfree(x); - kfree(xp); - - return 0; -} - - #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { @@ -1377,8 +1054,6 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), - [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), - [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), }; #undef XMSGSIZE @@ -1396,15 +1071,10 @@ static struct xfrm_link { [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, .dump = xfrm_dump_policy }, [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, - [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, - [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, - [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, - [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, - [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, }; static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) @@ -1486,26 +1156,26 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) unsigned int qlen = 0; do { - mutex_lock(&xfrm_cfg_mutex); + down(&xfrm_cfg_sem); netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); - mutex_unlock(&xfrm_cfg_mutex); + up(&xfrm_cfg_sem); } while (qlen); } -static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) +static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) { struct xfrm_user_expire *ue; struct nlmsghdr *nlh; unsigned char *b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, + nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE, sizeof(*ue)); ue = NLMSG_DATA(nlh); nlh->nlmsg_flags = 0; copy_to_user_state(x, &ue->state); - ue->hard = (c->data.hard != 0) ? 1 : 0; + ue->hard = (hard != 0) ? 1 : 0; nlh->nlmsg_len = skb->tail - b; return skb->len; @@ -1524,31 +1194,13 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) if (skb == NULL) return -ENOMEM; - if (build_expire(skb, x, c) < 0) + if (build_expire(skb, x, c->data.hard) < 0) BUG(); NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } -static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) -{ - struct sk_buff *skb; - int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); - - len += RTA_SPACE(sizeof(struct xfrm_replay_state)); - len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); - skb = alloc_skb(len, GFP_ATOMIC); - if (skb == NULL) - return -ENOMEM; - - if (build_aevent(skb, x, c) < 0) - BUG(); - - NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; - return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); -} - static int xfrm_notify_sa_flush(struct km_event *c) { struct xfrm_usersa_flush *p; @@ -1661,8 +1313,6 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) switch (c->event) { case XFRM_MSG_EXPIRE: return xfrm_exp_state_notify(x, c); - case XFRM_MSG_NEWAE: - return xfrm_aevent_state_notify(x, c); case XFRM_MSG_DELSA: case XFRM_MSG_UPDSA: case XFRM_MSG_NEWSA: @@ -1793,14 +1443,13 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, } static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, - int dir, struct km_event *c) + int dir, int hard) { struct xfrm_user_polexpire *upe; struct nlmsghdr *nlh; - int hard = c->data.hard; unsigned char *b = skb->tail; - nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); + nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); upe = NLMSG_DATA(nlh); nlh->nlmsg_flags = 0; @@ -1831,7 +1480,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve if (skb == NULL) return -ENOMEM; - if (build_polexpire(skb, xp, dir, c) < 0) + if (build_polexpire(skb, xp, dir, c->data.hard) < 0) BUG(); NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; @@ -1947,15 +1596,12 @@ static struct xfrm_mgr netlink_mgr = { static int __init xfrm_user_init(void) { - struct sock *nlsk; - printk(KERN_INFO "Initializing IPsec netlink socket\n"); - nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, - xfrm_netlink_rcv, THIS_MODULE); - if (nlsk == NULL) + xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, + xfrm_netlink_rcv, THIS_MODULE); + if (xfrm_nl == NULL) return -ENOMEM; - rcu_assign_pointer(xfrm_nl, nlsk); xfrm_register_km(&netlink_mgr); @@ -1964,16 +1610,11 @@ static int __init xfrm_user_init(void) static void __exit xfrm_user_exit(void) { - struct sock *nlsk = xfrm_nl; - xfrm_unregister_km(&netlink_mgr); - rcu_assign_pointer(xfrm_nl, NULL); - synchronize_rcu(); - sock_release(nlsk->sk_socket); + sock_release(xfrm_nl->sk_socket); } module_init(xfrm_user_init); module_exit(xfrm_user_exit); MODULE_LICENSE("GPL"); MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); -