ipsec: be careful of non existing mac headers
authorEric Dumazet <eric.dumazet@gmail.com>
Thu, 23 Feb 2012 10:55:02 +0000 (10:55 +0000)
committerWilly Tarreau <w@1wt.eu>
Sun, 7 Oct 2012 21:37:32 +0000 (23:37 +0200)
[ Upstream commit 03606895cd98c0a628b17324fd7b5ff15db7e3cd ]

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>
include/linux/skbuff.h
net/ipv4/xfrm4_mode_beet.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv6/xfrm6_mode_beet.c
net/ipv6/xfrm6_mode_tunnel.c

index bcdd6606f46876c16a9dd64ab41639b77c12740e..4e647bbda2dd8d093cefde794656b73d5e98743d 100644 (file)
@@ -1312,6 +1312,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_transport_offset(const struct sk_buff *skb)
 {
        return skb_transport_header(skb) - skb->data;
index 63418185f5249aaba6a8ae55be365536a56397a1..e3db3f9151146a6d393293e4e75daa63c988df1a 100644 (file)
@@ -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);
 
index 3444f3b34ecae4cb964f0fa84b1627bed1573b06..5d1d1fdbc1f26ddda6257db3111a5684e87a6efd 100644 (file)
@@ -65,7 +65,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)
@@ -83,10 +82,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:
index bbd48b101baeebada8a69f5eda7f7ad5087910db..6cc7a45e2d043b164fa3a00e25dfdada5f9c00b8 100644 (file)
@@ -82,7 +82,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;
 
@@ -92,10 +91,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);
 
index 3927832227b933d3fd55218e0bdb15c6369a7e0f..672c0da70c58bee28b4141e3413f4cbac3dda617 100644 (file)
@@ -61,7 +61,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;
@@ -78,10 +77,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: