xfrm: Add xfrm_tunnel_skb_cb to the skb common buffer
IPsec vti_rcv needs to remind the tunnel pointer to check it later at the vti_rcv_cb callback. So add this pointer to the IPsec common buffer, initialize it and check it to avoid transport state matching of a tunneled packet. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
parent
d099160e02
commit
70be6c91c8
3 changed files with 50 additions and 12 deletions
|
@ -599,16 +599,27 @@ struct xfrm_mgr {
|
|||
int xfrm_register_km(struct xfrm_mgr *km);
|
||||
int xfrm_unregister_km(struct xfrm_mgr *km);
|
||||
|
||||
struct xfrm_tunnel_skb_cb {
|
||||
union {
|
||||
struct inet_skb_parm h4;
|
||||
struct inet6_skb_parm h6;
|
||||
} header;
|
||||
|
||||
union {
|
||||
struct ip_tunnel *ip4;
|
||||
struct ip6_tnl *ip6;
|
||||
} tunnel;
|
||||
};
|
||||
|
||||
#define XFRM_TUNNEL_SKB_CB(__skb) ((struct xfrm_tunnel_skb_cb *)&((__skb)->cb[0]))
|
||||
|
||||
/*
|
||||
* This structure is used for the duration where packets are being
|
||||
* transformed by IPsec. As soon as the packet leaves IPsec the
|
||||
* area beyond the generic IP part may be overwritten.
|
||||
*/
|
||||
struct xfrm_skb_cb {
|
||||
union {
|
||||
struct inet_skb_parm h4;
|
||||
struct inet6_skb_parm h6;
|
||||
} header;
|
||||
struct xfrm_tunnel_skb_cb header;
|
||||
|
||||
/* Sequence number for replay protection. */
|
||||
union {
|
||||
|
@ -630,10 +641,7 @@ struct xfrm_skb_cb {
|
|||
* to transmit header information to the mode input/output functions.
|
||||
*/
|
||||
struct xfrm_mode_skb_cb {
|
||||
union {
|
||||
struct inet_skb_parm h4;
|
||||
struct inet6_skb_parm h6;
|
||||
} header;
|
||||
struct xfrm_tunnel_skb_cb header;
|
||||
|
||||
/* Copied from header for IPv4, always set to zero and DF for IPv6. */
|
||||
__be16 id;
|
||||
|
@ -665,10 +673,7 @@ struct xfrm_mode_skb_cb {
|
|||
* related information.
|
||||
*/
|
||||
struct xfrm_spi_skb_cb {
|
||||
union {
|
||||
struct inet_skb_parm h4;
|
||||
struct inet6_skb_parm h6;
|
||||
} header;
|
||||
struct xfrm_tunnel_skb_cb header;
|
||||
|
||||
unsigned int daddroff;
|
||||
unsigned int family;
|
||||
|
@ -1510,6 +1515,7 @@ int xfrm4_rcv(struct sk_buff *skb);
|
|||
|
||||
static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
|
||||
{
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
|
||||
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
|
||||
return xfrm_input(skb, nexthdr, spi, 0);
|
||||
|
@ -1781,4 +1787,24 @@ static inline int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
|
||||
unsigned int family)
|
||||
{
|
||||
bool tunnel = false;
|
||||
|
||||
switch(family) {
|
||||
case AF_INET:
|
||||
if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
|
||||
tunnel = true;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
|
||||
tunnel = true;
|
||||
break;
|
||||
}
|
||||
if (tunnel && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* _NET_XFRM_H */
|
||||
|
|
|
@ -65,6 +65,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
|
|||
int ret;
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
|
||||
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
|
||||
|
||||
|
@ -84,6 +85,8 @@ static int xfrm4_esp_rcv(struct sk_buff *skb)
|
|||
int ret;
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||
|
||||
for_each_protocol_rcu(esp4_handlers, handler)
|
||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||
return ret;
|
||||
|
@ -108,6 +111,8 @@ static int xfrm4_ah_rcv(struct sk_buff *skb)
|
|||
int ret;
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||
|
||||
for_each_protocol_rcu(ah4_handlers, handler)
|
||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||
return ret;;
|
||||
|
@ -132,6 +137,8 @@ static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
|
|||
int ret;
|
||||
struct xfrm4_protocol *handler;
|
||||
|
||||
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||
|
||||
for_each_protocol_rcu(ipcomp4_handlers, handler)
|
||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||
return ret;
|
||||
|
|
|
@ -163,6 +163,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
|
||||
skb->sp->xvec[skb->sp->len++] = x;
|
||||
|
||||
if (xfrm_tunnel_check(skb, x, family)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
spin_lock(&x->lock);
|
||||
if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
|
||||
|
|
Loading…
Reference in a new issue