mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 04:41:26 +00:00
[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>
This commit is contained in:
parent
68325d3b12
commit
050f009e16
@ -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 sk_buff *skb;
|
||||||
struct sadb_msg *hdr;
|
struct sadb_msg *hdr;
|
||||||
@ -1009,6 +1010,24 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
|
|||||||
return skb;
|
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,
|
static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
|
||||||
void **ext_hdrs)
|
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);
|
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)) {
|
if (IS_ERR(resp_skb)) {
|
||||||
xfrm_state_put(x);
|
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 sk_buff *skb;
|
||||||
struct sadb_msg *hdr;
|
struct sadb_msg *hdr;
|
||||||
int hsc = 3;
|
|
||||||
|
|
||||||
if (c->event == XFRM_MSG_DELSA)
|
skb = pfkey_xfrm_state2msg(x);
|
||||||
hsc = 0;
|
|
||||||
|
|
||||||
skb = pfkey_xfrm_state2msg(x, 0, hsc);
|
|
||||||
|
|
||||||
if (IS_ERR(skb))
|
if (IS_ERR(skb))
|
||||||
return PTR_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)
|
if (x == NULL)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
out_skb = pfkey_xfrm_state2msg(x, 1, 3);
|
out_skb = pfkey_xfrm_state2msg(x);
|
||||||
proto = x->id.proto;
|
proto = x->id.proto;
|
||||||
xfrm_state_put(x);
|
xfrm_state_put(x);
|
||||||
if (IS_ERR(out_skb))
|
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 sk_buff *out_skb;
|
||||||
struct sadb_msg *out_hdr;
|
struct sadb_msg *out_hdr;
|
||||||
|
|
||||||
out_skb = pfkey_xfrm_state2msg(x, 1, 3);
|
out_skb = pfkey_xfrm_state2msg(x);
|
||||||
if (IS_ERR(out_skb))
|
if (IS_ERR(out_skb))
|
||||||
return PTR_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
|
else
|
||||||
hsc = 1;
|
hsc = 1;
|
||||||
|
|
||||||
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
|
out_skb = pfkey_xfrm_state2msg_expire(x, hsc);
|
||||||
if (IS_ERR(out_skb))
|
if (IS_ERR(out_skb))
|
||||||
return PTR_ERR(out_skb);
|
return PTR_ERR(out_skb);
|
||||||
|
|
||||||
|
@ -507,8 +507,16 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
|
|||||||
struct xfrm_usersa_info *p,
|
struct xfrm_usersa_info *p,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
spin_lock_bh(&x->lock);
|
||||||
copy_to_user_state(x, p);
|
copy_to_user_state(x, p);
|
||||||
|
|
||||||
|
if (x->coaddr)
|
||||||
|
NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
|
||||||
|
|
||||||
|
if (x->lastused)
|
||||||
|
NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
|
||||||
|
spin_unlock_bh(&x->lock);
|
||||||
|
|
||||||
if (x->aalg)
|
if (x->aalg)
|
||||||
NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg);
|
NLA_PUT(skb, XFRMA_ALG_AUTH, alg_len(x->aalg), x->aalg);
|
||||||
if (x->ealg)
|
if (x->ealg)
|
||||||
@ -522,12 +530,6 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
|
|||||||
if (x->security && copy_sec_ctx(x->security, skb) < 0)
|
if (x->security && copy_sec_ctx(x->security, skb) < 0)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
if (x->coaddr)
|
|
||||||
NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
|
|
||||||
|
|
||||||
if (x->lastused)
|
|
||||||
NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
|
Loading…
Reference in New Issue
Block a user