Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipsec: be careful of non existing mac headers

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>

authored by

Eric Dumazet and committed by
David S. Miller
03606895 4a2258dd

+16 -17
+10
include/linux/skbuff.h
··· 1465 1465 } 1466 1466 #endif /* NET_SKBUFF_DATA_USES_OFFSET */ 1467 1467 1468 + static inline void skb_mac_header_rebuild(struct sk_buff *skb) 1469 + { 1470 + if (skb_mac_header_was_set(skb)) { 1471 + const unsigned char *old_mac = skb_mac_header(skb); 1472 + 1473 + skb_set_mac_header(skb, -skb->mac_len); 1474 + memmove(skb_mac_header(skb), old_mac, skb->mac_len); 1475 + } 1476 + } 1477 + 1468 1478 static inline int skb_checksum_start_offset(const struct sk_buff *skb) 1469 1479 { 1470 1480 return skb->csum_start - skb_headroom(skb);
+1 -4
net/ipv4/xfrm4_mode_beet.c
··· 110 110 111 111 skb_push(skb, sizeof(*iph)); 112 112 skb_reset_network_header(skb); 113 - 114 - memmove(skb->data - skb->mac_len, skb_mac_header(skb), 115 - skb->mac_len); 116 - skb_set_mac_header(skb, -skb->mac_len); 113 + skb_mac_header_rebuild(skb); 117 114 118 115 xfrm4_beet_make_header(skb); 119 116
+2 -4
net/ipv4/xfrm4_mode_tunnel.c
··· 66 66 67 67 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 68 68 { 69 - const unsigned char *old_mac; 70 69 int err = -EINVAL; 71 70 72 71 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) ··· 83 84 if (!(x->props.flags & XFRM_STATE_NOECN)) 84 85 ipip_ecn_decapsulate(skb); 85 86 86 - old_mac = skb_mac_header(skb); 87 - skb_set_mac_header(skb, -skb->mac_len); 88 - memmove(skb_mac_header(skb), old_mac, skb->mac_len); 89 87 skb_reset_network_header(skb); 88 + skb_mac_header_rebuild(skb); 89 + 90 90 err = 0; 91 91 92 92 out:
+1 -5
net/ipv6/xfrm6_mode_beet.c
··· 80 80 static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) 81 81 { 82 82 struct ipv6hdr *ip6h; 83 - const unsigned char *old_mac; 84 83 int size = sizeof(struct ipv6hdr); 85 84 int err; 86 85 ··· 89 90 90 91 __skb_push(skb, size); 91 92 skb_reset_network_header(skb); 92 - 93 - old_mac = skb_mac_header(skb); 94 - skb_set_mac_header(skb, -skb->mac_len); 95 - memmove(skb_mac_header(skb), old_mac, skb->mac_len); 93 + skb_mac_header_rebuild(skb); 96 94 97 95 xfrm6_beet_make_header(skb); 98 96
+2 -4
net/ipv6/xfrm6_mode_tunnel.c
··· 63 63 static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) 64 64 { 65 65 int err = -EINVAL; 66 - const unsigned char *old_mac; 67 66 68 67 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) 69 68 goto out; ··· 79 80 if (!(x->props.flags & XFRM_STATE_NOECN)) 80 81 ipip6_ecn_decapsulate(skb); 81 82 82 - old_mac = skb_mac_header(skb); 83 - skb_set_mac_header(skb, -skb->mac_len); 84 - memmove(skb_mac_header(skb), old_mac, skb->mac_len); 85 83 skb_reset_network_header(skb); 84 + skb_mac_header_rebuild(skb); 85 + 86 86 err = 0; 87 87 88 88 out: