Skip to content

Commit 2a3caba

Browse files
LorenzoBianconidavem330
authored andcommitted
net: ip6_gre: fix possible use-after-free in ip6erspan_rcv
erspan_v6 tunnels run __iptunnel_pull_header on received skbs to remove erspan header. This can determine a possible use-after-free accessing pkt_md pointer in ip6erspan_rcv since the packet will be 'uncloned' running pskb_expand_head if it is a cloned gso skb (e.g if the packet has been sent though a veth device). Fix it resetting pkt_md pointer after __iptunnel_pull_header Fixes: 1d7e2ed ("net: erspan: refactor existing erspan code") Signed-off-by: Lorenzo Bianconi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 492b67e commit 2a3caba

File tree

1 file changed

+13
-7
lines changed

1 file changed

+13
-7
lines changed

net/ipv6/ip6_gre.c

+13-7
Original file line numberDiff line numberDiff line change
@@ -525,10 +525,10 @@ static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
525525
}
526526

527527
static int ip6erspan_rcv(struct sk_buff *skb,
528-
struct tnl_ptk_info *tpi)
528+
struct tnl_ptk_info *tpi,
529+
int gre_hdr_len)
529530
{
530531
struct erspan_base_hdr *ershdr;
531-
struct erspan_metadata *pkt_md;
532532
const struct ipv6hdr *ipv6h;
533533
struct erspan_md2 *md2;
534534
struct ip6_tnl *tunnel;
@@ -547,18 +547,16 @@ static int ip6erspan_rcv(struct sk_buff *skb,
547547
if (unlikely(!pskb_may_pull(skb, len)))
548548
return PACKET_REJECT;
549549

550-
ershdr = (struct erspan_base_hdr *)skb->data;
551-
pkt_md = (struct erspan_metadata *)(ershdr + 1);
552-
553550
if (__iptunnel_pull_header(skb, len,
554551
htons(ETH_P_TEB),
555552
false, false) < 0)
556553
return PACKET_REJECT;
557554

558555
if (tunnel->parms.collect_md) {
556+
struct erspan_metadata *pkt_md, *md;
559557
struct metadata_dst *tun_dst;
560558
struct ip_tunnel_info *info;
561-
struct erspan_metadata *md;
559+
unsigned char *gh;
562560
__be64 tun_id;
563561
__be16 flags;
564562

@@ -571,6 +569,14 @@ static int ip6erspan_rcv(struct sk_buff *skb,
571569
if (!tun_dst)
572570
return PACKET_REJECT;
573571

572+
/* skb can be uncloned in __iptunnel_pull_header, so
573+
* old pkt_md is no longer valid and we need to reset
574+
* it
575+
*/
576+
gh = skb_network_header(skb) +
577+
skb_network_header_len(skb);
578+
pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
579+
sizeof(*ershdr));
574580
info = &tun_dst->u.tun_info;
575581
md = ip_tunnel_info_opts(info);
576582
md->version = ver;
@@ -607,7 +613,7 @@ static int gre_rcv(struct sk_buff *skb)
607613

608614
if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
609615
tpi.proto == htons(ETH_P_ERSPAN2))) {
610-
if (ip6erspan_rcv(skb, &tpi) == PACKET_RCVD)
616+
if (ip6erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
611617
return 0;
612618
goto out;
613619
}

0 commit comments

Comments
 (0)