143 lines
4.6 KiB
Diff
143 lines
4.6 KiB
Diff
From: Eric Dumazet <eric.dumazet@gmail.com>
|
|
Date: Thu, 23 Feb 2012 10:55:02 +0000
|
|
Subject: [PATCH] ipsec: be careful of non existing mac headers
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
commit 03606895cd98c0a628b17324fd7b5ff15db7e3cd upstream.
|
|
|
|
Niccolo Belli reported ipsec crashes in case we handle a frame without
|
|
mac header (atm in his case)
|
|
|
|
Before copying mac header, better make sure it is present.
|
|
|
|
Bugzilla reference: https://bugzilla.kernel.org/show_bug.cgi?id=42809
|
|
|
|
Reported-by: Niccolò Belli <darkbasic@linuxsystems.it>
|
|
Tested-by: Niccolò Belli <darkbasic@linuxsystems.it>
|
|
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
include/linux/skbuff.h | 10 ++++++++++
|
|
net/ipv4/xfrm4_mode_beet.c | 5 +----
|
|
net/ipv4/xfrm4_mode_tunnel.c | 6 ++----
|
|
net/ipv6/xfrm6_mode_beet.c | 6 +-----
|
|
net/ipv6/xfrm6_mode_tunnel.c | 6 ++----
|
|
5 files changed, 16 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
|
index 50db9b0..ae86ade 100644
|
|
--- a/include/linux/skbuff.h
|
|
+++ b/include/linux/skbuff.h
|
|
@@ -1465,6 +1465,16 @@ static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
|
|
}
|
|
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
|
|
|
|
+static inline void skb_mac_header_rebuild(struct sk_buff *skb)
|
|
+{
|
|
+ if (skb_mac_header_was_set(skb)) {
|
|
+ const unsigned char *old_mac = skb_mac_header(skb);
|
|
+
|
|
+ skb_set_mac_header(skb, -skb->mac_len);
|
|
+ memmove(skb_mac_header(skb), old_mac, skb->mac_len);
|
|
+ }
|
|
+}
|
|
+
|
|
static inline int skb_checksum_start_offset(const struct sk_buff *skb)
|
|
{
|
|
return skb->csum_start - skb_headroom(skb);
|
|
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
|
|
index 6341818..e3db3f9 100644
|
|
--- a/net/ipv4/xfrm4_mode_beet.c
|
|
+++ b/net/ipv4/xfrm4_mode_beet.c
|
|
@@ -110,10 +110,7 @@ static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
|
skb_push(skb, sizeof(*iph));
|
|
skb_reset_network_header(skb);
|
|
-
|
|
- memmove(skb->data - skb->mac_len, skb_mac_header(skb),
|
|
- skb->mac_len);
|
|
- skb_set_mac_header(skb, -skb->mac_len);
|
|
+ skb_mac_header_rebuild(skb);
|
|
|
|
xfrm4_beet_make_header(skb);
|
|
|
|
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
|
|
index 534972e..ed4bf11 100644
|
|
--- a/net/ipv4/xfrm4_mode_tunnel.c
|
|
+++ b/net/ipv4/xfrm4_mode_tunnel.c
|
|
@@ -66,7 +66,6 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
|
static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
- const unsigned char *old_mac;
|
|
int err = -EINVAL;
|
|
|
|
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
|
|
@@ -84,10 +83,9 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
if (!(x->props.flags & XFRM_STATE_NOECN))
|
|
ipip_ecn_decapsulate(skb);
|
|
|
|
- old_mac = skb_mac_header(skb);
|
|
- skb_set_mac_header(skb, -skb->mac_len);
|
|
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
|
|
skb_reset_network_header(skb);
|
|
+ skb_mac_header_rebuild(skb);
|
|
+
|
|
err = 0;
|
|
|
|
out:
|
|
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
|
|
index a81ce94..9949a35 100644
|
|
--- a/net/ipv6/xfrm6_mode_beet.c
|
|
+++ b/net/ipv6/xfrm6_mode_beet.c
|
|
@@ -80,7 +80,6 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
struct ipv6hdr *ip6h;
|
|
- const unsigned char *old_mac;
|
|
int size = sizeof(struct ipv6hdr);
|
|
int err;
|
|
|
|
@@ -90,10 +89,7 @@ static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
|
__skb_push(skb, size);
|
|
skb_reset_network_header(skb);
|
|
-
|
|
- old_mac = skb_mac_header(skb);
|
|
- skb_set_mac_header(skb, -skb->mac_len);
|
|
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
|
|
+ skb_mac_header_rebuild(skb);
|
|
|
|
xfrm6_beet_make_header(skb);
|
|
|
|
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
|
|
index 261e6e6..9f2095b 100644
|
|
--- a/net/ipv6/xfrm6_mode_tunnel.c
|
|
+++ b/net/ipv6/xfrm6_mode_tunnel.c
|
|
@@ -63,7 +63,6 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
int err = -EINVAL;
|
|
- const unsigned char *old_mac;
|
|
|
|
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
|
|
goto out;
|
|
@@ -80,10 +79,9 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
|
|
if (!(x->props.flags & XFRM_STATE_NOECN))
|
|
ipip6_ecn_decapsulate(skb);
|
|
|
|
- old_mac = skb_mac_header(skb);
|
|
- skb_set_mac_header(skb, -skb->mac_len);
|
|
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
|
|
skb_reset_network_header(skb);
|
|
+ skb_mac_header_rebuild(skb);
|
|
+
|
|
err = 0;
|
|
|
|
out:
|
|
--
|
|
1.7.9.1
|
|
|