summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2017-12-26 17:34:44 +1100
committerSteffen Klassert <steffen.klassert@secunet.com>2017-12-30 09:18:47 +0100
commit257a4b018d1b514a1cc738e3ca11b566d8f3a3d8 (patch)
treeb86e12edd8a20956c7e139fd754ba7adcebaf3c6 /net
parent2758b3e3e630ba304fc4aca434d591e70e528298 (diff)
downloadlinux-257a4b018d1b514a1cc738e3ca11b566d8f3a3d8.tar.gz
linux-257a4b018d1b514a1cc738e3ca11b566d8f3a3d8.tar.bz2
linux-257a4b018d1b514a1cc738e3ca11b566d8f3a3d8.zip
xfrm: Forbid state updates from changing encap type
Currently we allow state updates to competely replace the contents of x->encap. This is bad because on the user side ESP only sets up header lengths depending on encap_type once when the state is first created. This could result in the header lengths getting out of sync with the actual state configuration. In practice key managers will never do a state update to change the encapsulation type. Only the port numbers need to be changed as the peer NAT entry is updated. Therefore this patch adds a check in xfrm_state_update to forbid any changes to the encap_type. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net')
-rw-r--r--net/xfrm/xfrm_state.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 500b3391f474..1e80f68e2266 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1534,8 +1534,12 @@ out:
err = -EINVAL;
spin_lock_bh(&x1->lock);
if (likely(x1->km.state == XFRM_STATE_VALID)) {
- if (x->encap && x1->encap)
+ if (x->encap && x1->encap &&
+ x->encap->encap_type == x1->encap->encap_type)
memcpy(x1->encap, x->encap, sizeof(*x1->encap));
+ else if (x->encap || x1->encap)
+ goto fail;
+
if (x->coaddr && x1->coaddr) {
memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr));
}
@@ -1552,6 +1556,8 @@ out:
x->km.state = XFRM_STATE_DEAD;
__xfrm_state_put(x);
}
+
+fail:
spin_unlock_bh(&x1->lock);
xfrm_state_put(x1);