Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2015-05-28 1) Fix a race in xfrm_state_lookup_byspi, we need to take the refcount before we release xfrm_state_lock. From Li RongQing. 2) Fix IV generation on ESN state. We used just the low order sequence numbers for IV generation on ESN, as a result the IV can repeat on the same state. Fix this by using the high order sequence number bits too and make sure to always initialize the high order bits with zero. These patches are serious stable candidates. Fixes from Herbert Xu. 3) Fix the skb->mark handling on vti. We don't reset skb->mark in skb_scrub_packet anymore, so vti must care to restore the original value back after it was used to lookup the vti policy and state. Fixes from Alexander Duyck. Please pull or let me know if there are problems. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
5aab0e8a45
|
@ -256,7 +256,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||
aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
|
||||
aead_givcrypt_set_assoc(req, asg, assoclen);
|
||||
aead_givcrypt_set_giv(req, esph->enc_data,
|
||||
XFRM_SKB_CB(skb)->seq.output.low);
|
||||
XFRM_SKB_CB(skb)->seq.output.low +
|
||||
((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
|
||||
|
||||
ESP_SKB_CB(skb)->tmp = tmp;
|
||||
err = crypto_aead_givencrypt(req);
|
||||
|
|
|
@ -65,7 +65,6 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi,
|
|||
goto drop;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;
|
||||
skb->mark = be32_to_cpu(tunnel->parms.i_key);
|
||||
|
||||
return xfrm_input(skb, nexthdr, spi, encap_type);
|
||||
}
|
||||
|
@ -91,6 +90,8 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
|
|||
struct pcpu_sw_netstats *tstats;
|
||||
struct xfrm_state *x;
|
||||
struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4;
|
||||
u32 orig_mark = skb->mark;
|
||||
int ret;
|
||||
|
||||
if (!tunnel)
|
||||
return 1;
|
||||
|
@ -107,7 +108,11 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
|
|||
x = xfrm_input_state(skb);
|
||||
family = x->inner_mode->afinfo->family;
|
||||
|
||||
if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
|
||||
skb->mark = be32_to_cpu(tunnel->parms.i_key);
|
||||
ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family);
|
||||
skb->mark = orig_mark;
|
||||
|
||||
if (!ret)
|
||||
return -EPERM;
|
||||
|
||||
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev)));
|
||||
|
@ -216,8 +221,6 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
|
||||
skb->mark = be32_to_cpu(tunnel->parms.o_key);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
xfrm_decode_session(skb, &fl, AF_INET);
|
||||
|
@ -233,6 +236,9 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
/* override mark with tunnel output key */
|
||||
fl.flowi_mark = be32_to_cpu(tunnel->parms.o_key);
|
||||
|
||||
return vti_xmit(skb, dev, &fl);
|
||||
}
|
||||
|
||||
|
|
|
@ -248,7 +248,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||
aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
|
||||
aead_givcrypt_set_assoc(req, asg, assoclen);
|
||||
aead_givcrypt_set_giv(req, esph->enc_data,
|
||||
XFRM_SKB_CB(skb)->seq.output.low);
|
||||
XFRM_SKB_CB(skb)->seq.output.low +
|
||||
((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
|
||||
|
||||
ESP_SKB_CB(skb)->tmp = tmp;
|
||||
err = crypto_aead_givencrypt(req);
|
||||
|
|
|
@ -322,7 +322,6 @@ static int vti6_rcv(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
|
||||
skb->mark = be32_to_cpu(t->parms.i_key);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -342,6 +341,8 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err)
|
|||
struct pcpu_sw_netstats *tstats;
|
||||
struct xfrm_state *x;
|
||||
struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
|
||||
u32 orig_mark = skb->mark;
|
||||
int ret;
|
||||
|
||||
if (!t)
|
||||
return 1;
|
||||
|
@ -358,7 +359,11 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err)
|
|||
x = xfrm_input_state(skb);
|
||||
family = x->inner_mode->afinfo->family;
|
||||
|
||||
if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
|
||||
skb->mark = be32_to_cpu(t->parms.i_key);
|
||||
ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family);
|
||||
skb->mark = orig_mark;
|
||||
|
||||
if (!ret)
|
||||
return -EPERM;
|
||||
|
||||
skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
|
||||
|
@ -495,7 +500,6 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
int ret;
|
||||
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
skb->mark = be32_to_cpu(t->parms.o_key);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IPV6):
|
||||
|
@ -516,6 +520,9 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
goto tx_err;
|
||||
}
|
||||
|
||||
/* override mark with tunnel output key */
|
||||
fl.flowi_mark = be32_to_cpu(t->parms.o_key);
|
||||
|
||||
ret = vti6_xmit(skb, dev, &fl);
|
||||
if (ret < 0)
|
||||
goto tx_err;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <net/dst.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
#include <net/ip6_tunnel.h>
|
||||
|
||||
static struct kmem_cache *secpath_cachep __read_mostly;
|
||||
|
||||
|
@ -186,6 +188,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
struct xfrm_state *x = NULL;
|
||||
xfrm_address_t *daddr;
|
||||
struct xfrm_mode *inner_mode;
|
||||
u32 mark = skb->mark;
|
||||
unsigned int family;
|
||||
int decaps = 0;
|
||||
int async = 0;
|
||||
|
@ -203,6 +206,18 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
XFRM_SPI_SKB_CB(skb)->daddroff);
|
||||
family = XFRM_SPI_SKB_CB(skb)->family;
|
||||
|
||||
/* if tunnel is present override skb->mark value with tunnel i_key */
|
||||
if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
|
||||
break;
|
||||
case AF_INET6:
|
||||
mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate new secpath or COW existing one. */
|
||||
if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
|
||||
struct sec_path *sp;
|
||||
|
@ -229,7 +244,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
goto drop;
|
||||
}
|
||||
|
||||
x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
|
||||
x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
|
||||
if (x == NULL) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
|
||||
xfrm_audit_state_notfound(skb, family, spi, seq);
|
||||
|
|
|
@ -99,6 +99,7 @@ static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
|
|||
|
||||
if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
|
||||
XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq;
|
||||
XFRM_SKB_CB(skb)->seq.output.hi = 0;
|
||||
if (unlikely(x->replay.oseq == 0)) {
|
||||
x->replay.oseq--;
|
||||
xfrm_audit_state_replay_overflow(x, skb);
|
||||
|
@ -177,6 +178,7 @@ static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
|
|||
|
||||
if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
|
||||
XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq;
|
||||
XFRM_SKB_CB(skb)->seq.output.hi = 0;
|
||||
if (unlikely(replay_esn->oseq == 0)) {
|
||||
replay_esn->oseq--;
|
||||
xfrm_audit_state_replay_overflow(x, skb);
|
||||
|
|
|
@ -927,8 +927,8 @@ struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
|
|||
x->id.spi != spi)
|
||||
continue;
|
||||
|
||||
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
|
||||
xfrm_state_hold(x);
|
||||
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
|
||||
return x;
|
||||
}
|
||||
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
|
||||
|
|
Загрузка…
Ссылка в новой задаче