diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-10-09 16:31:47 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:55:02 -0400 |
commit | 050f009e16f908932070313c1745d09dc69fd62b (patch) | |
tree | 2176b8034065bf2e8b401865efcfaab912bb1997 /net | |
parent | 68325d3b12ad5bce650c2883bb878257f197efff (diff) |
[IPSEC]: Lock state when copying non-atomic fields to user-space
This patch adds locking so that when we're copying non-atomic fields such as
life-time or coaddr to user-space we don't get a partial result.
For af_key I've changed every instance of pfkey_xfrm_state2msg apart from
expiration notification to include the keys and life-times. This is in-line
with XFRM behaviour.
The actual cases affected are:
* pfkey_getspi: No change as we don't have any keys to copy.
* key_notify_sa:
+ ADD/UPD: This wouldn't work otherwise.
+ DEL: It can't hurt.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/key/af_key.c | 35 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 14 |
2 files changed, 33 insertions, 16 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index 143d46f6329a..7969f8a716df 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -655,7 +655,8 @@ static inline int pfkey_mode_to_xfrm(int mode) | |||
655 | } | 655 | } |
656 | } | 656 | } |
657 | 657 | ||
658 | static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc) | 658 | static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, |
659 | int add_keys, int hsc) | ||
659 | { | 660 | { |
660 | struct sk_buff *skb; | 661 | struct sk_buff *skb; |
661 | struct sadb_msg *hdr; | 662 | struct sadb_msg *hdr; |
@@ -1009,6 +1010,24 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, | |||
1009 | return skb; | 1010 | return skb; |
1010 | } | 1011 | } |
1011 | 1012 | ||
1013 | |||
1014 | static inline struct sk_buff *pfkey_xfrm_state2msg(struct xfrm_state *x) | ||
1015 | { | ||
1016 | struct sk_buff *skb; | ||
1017 | |||
1018 | spin_lock_bh(&x->lock); | ||
1019 | skb = __pfkey_xfrm_state2msg(x, 1, 3); | ||
1020 | spin_unlock_bh(&x->lock); | ||
1021 | |||
1022 | return skb; | ||
1023 | } | ||
1024 | |||
1025 | static inline struct sk_buff *pfkey_xfrm_state2msg_expire(struct xfrm_state *x, | ||
1026 | int hsc) | ||
1027 | { | ||
1028 | return __pfkey_xfrm_state2msg(x, 0, hsc); | ||
1029 | } | ||
1030 | |||
1012 | static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, | 1031 | static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, |
1013 | void **ext_hdrs) | 1032 | void **ext_hdrs) |
1014 | { | 1033 | { |
@@ -1322,7 +1341,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
1322 | } | 1341 | } |
1323 | 1342 | ||
1324 | err = xfrm_alloc_spi(x, min_spi, max_spi); | 1343 | err = xfrm_alloc_spi(x, min_spi, max_spi); |
1325 | resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x, 0, 3); | 1344 | resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); |
1326 | 1345 | ||
1327 | if (IS_ERR(resp_skb)) { | 1346 | if (IS_ERR(resp_skb)) { |
1328 | xfrm_state_put(x); | 1347 | xfrm_state_put(x); |
@@ -1412,12 +1431,8 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c) | |||
1412 | { | 1431 | { |
1413 | struct sk_buff *skb; | 1432 | struct sk_buff *skb; |
1414 | struct sadb_msg *hdr; | 1433 | struct sadb_msg *hdr; |
1415 | int hsc = 3; | ||
1416 | |||
1417 | if (c->event == XFRM_MSG_DELSA) | ||
1418 | hsc = 0; | ||
1419 | 1434 | ||
1420 | skb = pfkey_xfrm_state2msg(x, 0, hsc); | 1435 | skb = pfkey_xfrm_state2msg(x); |
1421 | 1436 | ||
1422 | if (IS_ERR(skb)) | 1437 | if (IS_ERR(skb)) |
1423 | return PTR_ERR(skb); | 1438 | return PTR_ERR(skb); |
@@ -1529,7 +1544,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, | |||
1529 | if (x == NULL) | 1544 | if (x == NULL) |
1530 | return -ESRCH; | 1545 | return -ESRCH; |
1531 | 1546 | ||
1532 | out_skb = pfkey_xfrm_state2msg(x, 1, 3); | 1547 | out_skb = pfkey_xfrm_state2msg(x); |
1533 | proto = x->id.proto; | 1548 | proto = x->id.proto; |
1534 | xfrm_state_put(x); | 1549 | xfrm_state_put(x); |
1535 | if (IS_ERR(out_skb)) | 1550 | if (IS_ERR(out_skb)) |
@@ -1709,7 +1724,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) | |||
1709 | struct sk_buff *out_skb; | 1724 | struct sk_buff *out_skb; |
1710 | struct sadb_msg *out_hdr; | 1725 | struct sadb_msg *out_hdr; |
1711 | 1726 | ||
1712 | out_skb = pfkey_xfrm_state2msg(x, 1, 3); | 1727 | out_skb = pfkey_xfrm_state2msg(x); |
1713 | if (IS_ERR(out_skb)) | 1728 | if (IS_ERR(out_skb)) |
1714 | return PTR_ERR(out_skb); | 1729 | return PTR_ERR(out_skb); |
1715 | 1730 | ||
@@ -2910,7 +2925,7 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) | |||
2910 | else | 2925 | else |
2911 | hsc = 1; | 2926 | hsc = 1; |
2912 | 2927 | ||
2913 | out_skb = pfkey_xfrm_state2msg(x, 0, hsc); | 2928 | out_skb = pfkey_xfrm_state2msg_expire(x, hsc); |
2914 | if (IS_ERR(out_skb)) | 2929 | if (IS_ERR(out_skb)) |
2915 | return PTR_ERR(out_skb); | 2930 | return PTR_ERR(out_skb); |
2916 | 2931 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 2cbbe5e93a7b..5238f6a8dfad 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -507,8 +507,16 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
507 | struct xfrm_usersa_info *p, | 507 | struct xfrm_usersa_info *p, |
508 | struct sk_buff *skb) | 508 | struct sk_buff *skb) |
509 | { | 509 | { |
510 | spin_lock_bh(&x->lock); | ||
510 | copy_to_user_state(x, p); | 511 | copy_to_user_state(x, p); |
511 | 512 | ||
513 | if (x->coaddr) | ||
514 | NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | ||
515 | |||
516 | if (x->lastused) | ||
517 | NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); | ||
518 | spin_unlock_bh(&x->lock); | ||
519 | |||
512 | if (x->aalg) | 520 | if (x->aalg) |
513 | NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); | 521 | NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg); |
514 | if (x->ealg) | 522 | if (x->ealg) |
@@ -522,12 +530,6 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
522 | if (x->security && copy_sec_ctx(x->security, skb) < 0) | 530 | if (x->security && copy_sec_ctx(x->security, skb) < 0) |
523 | goto nla_put_failure; | 531 | goto nla_put_failure; |
524 | 532 | ||
525 | if (x->coaddr) | ||
526 | NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | ||
527 | |||
528 | if (x->lastused) | ||
529 | NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); | ||
530 | |||
531 | return 0; | 533 | return 0; |
532 | 534 | ||
533 | nla_put_failure: | 535 | nla_put_failure: |