summaryrefslogtreecommitdiffstats
path: root/net/key
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-10-09 22:31:47 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-11 01:55:02 +0200
commit050f009e16f908932070313c1745d09dc69fd62b (patch)
tree2176b8034065bf2e8b401865efcfaab912bb1997 /net/key
parent[XFRM] user: Move attribute copying code into copy_to_user_state_extra (diff)
downloadlinux-050f009e16f908932070313c1745d09dc69fd62b.tar.xz
linux-050f009e16f908932070313c1745d09dc69fd62b.zip
[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/key')
-rw-r--r--net/key/af_key.c35
1 files changed, 25 insertions, 10 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)
}
}
-static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc)
+static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
+ int add_keys, int hsc)
{
struct sk_buff *skb;
struct sadb_msg *hdr;
@@ -1009,6 +1010,24 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
return skb;
}
+
+static inline struct sk_buff *pfkey_xfrm_state2msg(struct xfrm_state *x)
+{
+ struct sk_buff *skb;
+
+ spin_lock_bh(&x->lock);
+ skb = __pfkey_xfrm_state2msg(x, 1, 3);
+ spin_unlock_bh(&x->lock);
+
+ return skb;
+}
+
+static inline struct sk_buff *pfkey_xfrm_state2msg_expire(struct xfrm_state *x,
+ int hsc)
+{
+ return __pfkey_xfrm_state2msg(x, 0, hsc);
+}
+
static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
void **ext_hdrs)
{
@@ -1322,7 +1341,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
}
err = xfrm_alloc_spi(x, min_spi, max_spi);
- resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x, 0, 3);
+ resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x);
if (IS_ERR(resp_skb)) {
xfrm_state_put(x);
@@ -1412,12 +1431,8 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
struct sadb_msg *hdr;
- int hsc = 3;
-
- if (c->event == XFRM_MSG_DELSA)
- hsc = 0;
- skb = pfkey_xfrm_state2msg(x, 0, hsc);
+ skb = pfkey_xfrm_state2msg(x);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -1529,7 +1544,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
if (x == NULL)
return -ESRCH;
- out_skb = pfkey_xfrm_state2msg(x, 1, 3);
+ out_skb = pfkey_xfrm_state2msg(x);
proto = x->id.proto;
xfrm_state_put(x);
if (IS_ERR(out_skb))
@@ -1709,7 +1724,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr)
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- out_skb = pfkey_xfrm_state2msg(x, 1, 3);
+ out_skb = pfkey_xfrm_state2msg(x);
if (IS_ERR(out_skb))
return PTR_ERR(out_skb);
@@ -2910,7 +2925,7 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
else
hsc = 1;
- out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
+ out_skb = pfkey_xfrm_state2msg_expire(x, hsc);
if (IS_ERR(out_skb))
return PTR_ERR(out_skb);