Unverified Commit 42bf10ff authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!6058 net: ip_tunnel: prevent perpetual headroom growth

parents 4ba93668 9f7f7a3f
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -540,6 +540,20 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
	return 0;
}

static void ip_tunnel_adj_headroom(struct net_device *dev, unsigned int headroom)
{
	/* we must cap headroom to some upperlimit, else pskb_expand_head
	 * will overflow header offsets in skb_headers_offset_update().
	 */
	static const unsigned int max_allowed = 512;

	if (headroom > max_allowed)
		headroom = max_allowed;

	if (headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, headroom);
}

void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		       u8 proto, int tunnel_hlen)
{
@@ -613,13 +627,13 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
	}

	headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
	if (headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, headroom);

	if (skb_cow_head(skb, READ_ONCE(dev->needed_headroom))) {
	if (skb_cow_head(skb, headroom)) {
		ip_rt_put(rt);
		goto tx_dropped;
	}

	ip_tunnel_adj_headroom(dev, headroom);

	iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
		      df, !net_eq(tunnel->net, dev_net(dev)));
	return;
@@ -797,16 +811,16 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,

	max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr)
			+ rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
	if (max_headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, max_headroom);

	if (skb_cow_head(skb, READ_ONCE(dev->needed_headroom))) {
	if (skb_cow_head(skb, max_headroom)) {
		ip_rt_put(rt);
		dev->stats.tx_dropped++;
		kfree_skb(skb);
		return;
	}

	ip_tunnel_adj_headroom(dev, max_headroom);

	iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
		      df, !net_eq(tunnel->net, dev_net(dev)));
	return;