diff options
author | Steffen Klassert <steffen.klassert@secunet.com> | 2011-03-07 19:10:27 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-13 23:22:31 -0400 |
commit | d8647b79c3b7e223ac051439d165bc8e7bbb832f (patch) | |
tree | c3d0e377c77f4c0c138c339c3ac0c66dbb1d232b /net/xfrm/xfrm_user.c | |
parent | 2cd084678fc1eb75aec4f7ae3d339d232c00ec61 (diff) |
xfrm: Add user interface for esn and big anti-replay windows
This patch adds a netlink based user interface to configure
esn and big anti-replay windows. The new netlink attribute
XFRMA_REPLAY_ESN_VAL is used to configure the new implementation.
If the XFRM_STATE_ESN flag is set, we use esn and support for big
anti-replay windows for the configured state. If this flag is not
set we use the new implementation with 32 bit sequence numbers.
A big anti-replay window can be configured in this case anyway.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 99 |
1 files changed, 85 insertions, 14 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f7b3c857c989..706385ae3e4b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -119,6 +119,19 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs) | |||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | static inline int verify_replay(struct xfrm_usersa_info *p, | ||
123 | struct nlattr **attrs) | ||
124 | { | ||
125 | struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; | ||
126 | |||
127 | if (!rt) | ||
128 | return 0; | ||
129 | |||
130 | if (p->replay_window != 0) | ||
131 | return -EINVAL; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
122 | 135 | ||
123 | static int verify_newsa_info(struct xfrm_usersa_info *p, | 136 | static int verify_newsa_info(struct xfrm_usersa_info *p, |
124 | struct nlattr **attrs) | 137 | struct nlattr **attrs) |
@@ -214,6 +227,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
214 | goto out; | 227 | goto out; |
215 | if ((err = verify_sec_ctx_len(attrs))) | 228 | if ((err = verify_sec_ctx_len(attrs))) |
216 | goto out; | 229 | goto out; |
230 | if ((err = verify_replay(p, attrs))) | ||
231 | goto out; | ||
217 | 232 | ||
218 | err = -EINVAL; | 233 | err = -EINVAL; |
219 | switch (p->mode) { | 234 | switch (p->mode) { |
@@ -345,6 +360,33 @@ static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, | |||
345 | return 0; | 360 | return 0; |
346 | } | 361 | } |
347 | 362 | ||
363 | static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn, | ||
364 | struct xfrm_replay_state_esn **preplay_esn, | ||
365 | struct nlattr *rta) | ||
366 | { | ||
367 | struct xfrm_replay_state_esn *p, *pp, *up; | ||
368 | |||
369 | if (!rta) | ||
370 | return 0; | ||
371 | |||
372 | up = nla_data(rta); | ||
373 | |||
374 | p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); | ||
375 | if (!p) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); | ||
379 | if (!pp) { | ||
380 | kfree(p); | ||
381 | return -ENOMEM; | ||
382 | } | ||
383 | |||
384 | *replay_esn = p; | ||
385 | *preplay_esn = pp; | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
348 | static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) | 390 | static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) |
349 | { | 391 | { |
350 | int len = 0; | 392 | int len = 0; |
@@ -380,10 +422,20 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
380 | static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) | 422 | static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) |
381 | { | 423 | { |
382 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; | 424 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; |
425 | struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; | ||
383 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 426 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
384 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; | 427 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; |
385 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; | 428 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; |
386 | 429 | ||
430 | if (re) { | ||
431 | struct xfrm_replay_state_esn *replay_esn; | ||
432 | replay_esn = nla_data(re); | ||
433 | memcpy(x->replay_esn, replay_esn, | ||
434 | xfrm_replay_state_esn_len(replay_esn)); | ||
435 | memcpy(x->preplay_esn, replay_esn, | ||
436 | xfrm_replay_state_esn_len(replay_esn)); | ||
437 | } | ||
438 | |||
387 | if (rp) { | 439 | if (rp) { |
388 | struct xfrm_replay_state *replay; | 440 | struct xfrm_replay_state *replay; |
389 | replay = nla_data(rp); | 441 | replay = nla_data(rp); |
@@ -467,13 +519,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
467 | security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX]))) | 519 | security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX]))) |
468 | goto error; | 520 | goto error; |
469 | 521 | ||
522 | if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn, | ||
523 | attrs[XFRMA_REPLAY_ESN_VAL]))) | ||
524 | goto error; | ||
525 | |||
470 | x->km.seq = p->seq; | 526 | x->km.seq = p->seq; |
471 | x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth; | 527 | x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth; |
472 | /* sysctl_xfrm_aevent_etime is in 100ms units */ | 528 | /* sysctl_xfrm_aevent_etime is in 100ms units */ |
473 | x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M; | 529 | x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M; |
474 | x->preplay.bitmap = 0; | ||
475 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; | ||
476 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; | ||
477 | 530 | ||
478 | if ((err = xfrm_init_replay(x))) | 531 | if ((err = xfrm_init_replay(x))) |
479 | goto error; | 532 | goto error; |
@@ -709,6 +762,10 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
709 | if (xfrm_mark_put(skb, &x->mark)) | 762 | if (xfrm_mark_put(skb, &x->mark)) |
710 | goto nla_put_failure; | 763 | goto nla_put_failure; |
711 | 764 | ||
765 | if (x->replay_esn) | ||
766 | NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL, | ||
767 | xfrm_replay_state_esn_len(x->replay_esn), x->replay_esn); | ||
768 | |||
712 | if (x->security && copy_sec_ctx(x->security, skb) < 0) | 769 | if (x->security && copy_sec_ctx(x->security, skb) < 0) |
713 | goto nla_put_failure; | 770 | goto nla_put_failure; |
714 | 771 | ||
@@ -1578,10 +1635,14 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1578 | return 0; | 1635 | return 0; |
1579 | } | 1636 | } |
1580 | 1637 | ||
1581 | static inline size_t xfrm_aevent_msgsize(void) | 1638 | static inline size_t xfrm_aevent_msgsize(struct xfrm_state *x) |
1582 | { | 1639 | { |
1640 | size_t replay_size = x->replay_esn ? | ||
1641 | xfrm_replay_state_esn_len(x->replay_esn) : | ||
1642 | sizeof(struct xfrm_replay_state); | ||
1643 | |||
1583 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) | 1644 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) |
1584 | + nla_total_size(sizeof(struct xfrm_replay_state)) | 1645 | + nla_total_size(replay_size) |
1585 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) | 1646 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) |
1586 | + nla_total_size(sizeof(struct xfrm_mark)) | 1647 | + nla_total_size(sizeof(struct xfrm_mark)) |
1587 | + nla_total_size(4) /* XFRM_AE_RTHR */ | 1648 | + nla_total_size(4) /* XFRM_AE_RTHR */ |
@@ -1606,7 +1667,13 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct | |||
1606 | id->reqid = x->props.reqid; | 1667 | id->reqid = x->props.reqid; |
1607 | id->flags = c->data.aevent; | 1668 | id->flags = c->data.aevent; |
1608 | 1669 | ||
1609 | NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | 1670 | if (x->replay_esn) |
1671 | NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL, | ||
1672 | xfrm_replay_state_esn_len(x->replay_esn), | ||
1673 | x->replay_esn); | ||
1674 | else | ||
1675 | NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | ||
1676 | |||
1610 | NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft); | 1677 | NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft); |
1611 | 1678 | ||
1612 | if (id->flags & XFRM_AE_RTHR) | 1679 | if (id->flags & XFRM_AE_RTHR) |
@@ -1639,16 +1706,16 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1639 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1706 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1640 | struct xfrm_usersa_id *id = &p->sa_id; | 1707 | struct xfrm_usersa_id *id = &p->sa_id; |
1641 | 1708 | ||
1642 | r_skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); | ||
1643 | if (r_skb == NULL) | ||
1644 | return -ENOMEM; | ||
1645 | |||
1646 | mark = xfrm_mark_get(attrs, &m); | 1709 | mark = xfrm_mark_get(attrs, &m); |
1647 | 1710 | ||
1648 | x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); | 1711 | x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); |
1649 | if (x == NULL) { | 1712 | if (x == NULL) |
1650 | kfree_skb(r_skb); | ||
1651 | return -ESRCH; | 1713 | return -ESRCH; |
1714 | |||
1715 | r_skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC); | ||
1716 | if (r_skb == NULL) { | ||
1717 | xfrm_state_put(x); | ||
1718 | return -ENOMEM; | ||
1652 | } | 1719 | } |
1653 | 1720 | ||
1654 | /* | 1721 | /* |
@@ -1680,9 +1747,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1680 | struct xfrm_mark m; | 1747 | struct xfrm_mark m; |
1681 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1748 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1682 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; | 1749 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; |
1750 | struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; | ||
1683 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 1751 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
1684 | 1752 | ||
1685 | if (!lt && !rp) | 1753 | if (!lt && !rp && !re) |
1686 | return err; | 1754 | return err; |
1687 | 1755 | ||
1688 | /* pedantic mode - thou shalt sayeth replaceth */ | 1756 | /* pedantic mode - thou shalt sayeth replaceth */ |
@@ -2147,6 +2215,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
2147 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | 2215 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, |
2148 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, | 2216 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, |
2149 | [XFRMA_TFCPAD] = { .type = NLA_U32 }, | 2217 | [XFRMA_TFCPAD] = { .type = NLA_U32 }, |
2218 | [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, | ||
2150 | }; | 2219 | }; |
2151 | 2220 | ||
2152 | static struct xfrm_link { | 2221 | static struct xfrm_link { |
@@ -2274,7 +2343,7 @@ static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event | |||
2274 | struct net *net = xs_net(x); | 2343 | struct net *net = xs_net(x); |
2275 | struct sk_buff *skb; | 2344 | struct sk_buff *skb; |
2276 | 2345 | ||
2277 | skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); | 2346 | skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC); |
2278 | if (skb == NULL) | 2347 | if (skb == NULL) |
2279 | return -ENOMEM; | 2348 | return -ENOMEM; |
2280 | 2349 | ||
@@ -2328,6 +2397,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2328 | l += nla_total_size(sizeof(*x->encap)); | 2397 | l += nla_total_size(sizeof(*x->encap)); |
2329 | if (x->tfcpad) | 2398 | if (x->tfcpad) |
2330 | l += nla_total_size(sizeof(x->tfcpad)); | 2399 | l += nla_total_size(sizeof(x->tfcpad)); |
2400 | if (x->replay_esn) | ||
2401 | l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn)); | ||
2331 | if (x->security) | 2402 | if (x->security) |
2332 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + | 2403 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + |
2333 | x->security->ctx_len); | 2404 | x->security->ctx_len); |