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_register_km(struct xfrm_mgr *km);
|
||||||
int xfrm_unregister_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
|
* This structure is used for the duration where packets are being
|
||||||
* transformed by IPsec. As soon as the packet leaves IPsec the
|
* transformed by IPsec. As soon as the packet leaves IPsec the
|
||||||
* area beyond the generic IP part may be overwritten.
|
* area beyond the generic IP part may be overwritten.
|
||||||
*/
|
*/
|
||||||
struct xfrm_skb_cb {
|
struct xfrm_skb_cb {
|
||||||
union {
|
struct xfrm_tunnel_skb_cb header;
|
||||||
struct inet_skb_parm h4;
|
|
||||||
struct inet6_skb_parm h6;
|
|
||||||
} header;
|
|
||||||
|
|
||||||
/* Sequence number for replay protection. */
|
/* Sequence number for replay protection. */
|
||||||
union {
|
union {
|
||||||
|
@ -630,10 +641,7 @@ struct xfrm_skb_cb {
|
||||||
* to transmit header information to the mode input/output functions.
|
* to transmit header information to the mode input/output functions.
|
||||||
*/
|
*/
|
||||||
struct xfrm_mode_skb_cb {
|
struct xfrm_mode_skb_cb {
|
||||||
union {
|
struct xfrm_tunnel_skb_cb header;
|
||||||
struct inet_skb_parm h4;
|
|
||||||
struct inet6_skb_parm h6;
|
|
||||||
} header;
|
|
||||||
|
|
||||||
/* Copied from header for IPv4, always set to zero and DF for IPv6. */
|
/* Copied from header for IPv4, always set to zero and DF for IPv6. */
|
||||||
__be16 id;
|
__be16 id;
|
||||||
|
@ -665,10 +673,7 @@ struct xfrm_mode_skb_cb {
|
||||||
* related information.
|
* related information.
|
||||||
*/
|
*/
|
||||||
struct xfrm_spi_skb_cb {
|
struct xfrm_spi_skb_cb {
|
||||||
union {
|
struct xfrm_tunnel_skb_cb header;
|
||||||
struct inet_skb_parm h4;
|
|
||||||
struct inet6_skb_parm h6;
|
|
||||||
} header;
|
|
||||||
|
|
||||||
unsigned int daddroff;
|
unsigned int daddroff;
|
||||||
unsigned int family;
|
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)
|
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)->family = AF_INET;
|
||||||
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
|
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
|
||||||
return xfrm_input(skb, nexthdr, spi, 0);
|
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;
|
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 */
|
#endif /* _NET_XFRM_H */
|
||||||
|
|
|
@ -65,6 +65,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
|
||||||
int ret;
|
int ret;
|
||||||
struct xfrm4_protocol *handler;
|
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)->family = AF_INET;
|
||||||
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
|
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;
|
int ret;
|
||||||
struct xfrm4_protocol *handler;
|
struct xfrm4_protocol *handler;
|
||||||
|
|
||||||
|
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||||
|
|
||||||
for_each_protocol_rcu(esp4_handlers, handler)
|
for_each_protocol_rcu(esp4_handlers, handler)
|
||||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -108,6 +111,8 @@ static int xfrm4_ah_rcv(struct sk_buff *skb)
|
||||||
int ret;
|
int ret;
|
||||||
struct xfrm4_protocol *handler;
|
struct xfrm4_protocol *handler;
|
||||||
|
|
||||||
|
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||||
|
|
||||||
for_each_protocol_rcu(ah4_handlers, handler)
|
for_each_protocol_rcu(ah4_handlers, handler)
|
||||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||||
return ret;;
|
return ret;;
|
||||||
|
@ -132,6 +137,8 @@ static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
|
||||||
int ret;
|
int ret;
|
||||||
struct xfrm4_protocol *handler;
|
struct xfrm4_protocol *handler;
|
||||||
|
|
||||||
|
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
|
||||||
|
|
||||||
for_each_protocol_rcu(ipcomp4_handlers, handler)
|
for_each_protocol_rcu(ipcomp4_handlers, handler)
|
||||||
if ((ret = handler->handler(skb)) != -EINVAL)
|
if ((ret = handler->handler(skb)) != -EINVAL)
|
||||||
return ret;
|
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;
|
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);
|
spin_lock(&x->lock);
|
||||||
if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
|
if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
|
||||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
|
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
|
||||||
|
|
Loading…
Add table
Reference in a new issue