Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/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>
  • Loading branch information
David S. Miller committed May 29, 2015
2 parents 210347e + d55c670 commit 5aab0e8
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 11 deletions.
3 changes: 2 additions & 1 deletion net/ipv4/esp4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 10 additions & 4 deletions net/ipv4/ip_vti.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
Expand All @@ -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)));
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
3 changes: 2 additions & 1 deletion net/ipv6/esp6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 10 additions & 3 deletions net/ipv6/ip6_vti.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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;
Expand All @@ -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)));
Expand Down Expand Up @@ -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):
Expand All @@ -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;
Expand Down
17 changes: 16 additions & 1 deletion net/xfrm/xfrm_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions net/xfrm/xfrm_replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion net/xfrm/xfrm_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 5aab0e8

Please sign in to comment.