Skip to content

Commit 3c5189a

Browse files
committed
Merge branch 'erspan-use-after-free'
Lorenzo Bianconi says: ==================== fix possible use-after-free in erspan_v{4,6} Similar to what I did in commit bb9bd81 ("ipv6: sit: reset ip header pointer in ipip6_rcv"), fix possible use-after-free in erspan_rcv and ip6erspan_rcv extracting tunnel metadata since the packet can be 'uncloned' running __iptunnel_pull_header ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents b75bb8a + 2a3caba commit 3c5189a

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

net/ipv4/ip_gre.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
259259
struct net *net = dev_net(skb->dev);
260260
struct metadata_dst *tun_dst = NULL;
261261
struct erspan_base_hdr *ershdr;
262-
struct erspan_metadata *pkt_md;
263262
struct ip_tunnel_net *itn;
264263
struct ip_tunnel *tunnel;
265264
const struct iphdr *iph;
@@ -282,18 +281,16 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
282281
if (unlikely(!pskb_may_pull(skb, len)))
283282
return PACKET_REJECT;
284283

285-
ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
286-
pkt_md = (struct erspan_metadata *)(ershdr + 1);
287-
288284
if (__iptunnel_pull_header(skb,
289285
len,
290286
htons(ETH_P_TEB),
291287
false, false) < 0)
292288
goto drop;
293289

294290
if (tunnel->collect_md) {
291+
struct erspan_metadata *pkt_md, *md;
295292
struct ip_tunnel_info *info;
296-
struct erspan_metadata *md;
293+
unsigned char *gh;
297294
__be64 tun_id;
298295
__be16 flags;
299296

@@ -306,6 +303,14 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
306303
if (!tun_dst)
307304
return PACKET_REJECT;
308305

306+
/* skb can be uncloned in __iptunnel_pull_header, so
307+
* old pkt_md is no longer valid and we need to reset
308+
* it
309+
*/
310+
gh = skb_network_header(skb) +
311+
skb_network_header_len(skb);
312+
pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len +
313+
sizeof(*ershdr));
309314
md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
310315
md->version = ver;
311316
md2 = &md->u.md2;

net/ipv6/ip6_gre.c

Lines changed: 13 additions & 7 deletions
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)