mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 16:53:20 -04:00
net: cap advertised IP tunnel headroom
IP tunnel devices derive their advertised needed_headroom from lower
output devices. A stack of user-created devices can make the derived
value larger than the 16-bit skb header offsets can represent. Once IP
output reserves it, skb head expansion can wrap those offsets.
The runtime transmit path already caps a growing needed_headroom at 512.
Apply the same cap when tunnel configuration publishes needed_headroom
derived from a lower output device.
Capping the advertised value is safe: IP tunnel transmit still expands
the skb when a packet needs more headroom. A nonsensical stacked
configuration can therefore incur an extra reallocation, but it cannot
publish an unbounded reservation to upper layers.
Fixes: 1a37e412a0 ("net: Use 16bits for *_headers fields of struct skbuff")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/ba04a1fd6bfae2377607fad5d8f80f7eb80fd4c4.1786542637.git.zhilinz@nebusec.ai
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -629,8 +629,7 @@ struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
|
||||
int skb_tunnel_check_pmtu(struct sk_buff *skb, struct dst_entry *encap_dst,
|
||||
int headroom, bool reply);
|
||||
|
||||
static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
unsigned int headroom)
|
||||
static inline unsigned int ip_tunnel_limit_headroom(unsigned int headroom)
|
||||
{
|
||||
/* we must cap headroom to some upperlimit, else pskb_expand_head
|
||||
* will overflow header offsets in skb_headers_offset_update().
|
||||
@@ -640,6 +639,14 @@ static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
if (headroom > max_allowed)
|
||||
headroom = max_allowed;
|
||||
|
||||
return headroom;
|
||||
}
|
||||
|
||||
static inline void ip_tunnel_adj_headroom(struct net_device *dev,
|
||||
unsigned int headroom)
|
||||
{
|
||||
headroom = ip_tunnel_limit_headroom(headroom);
|
||||
|
||||
if (headroom > READ_ONCE(dev->needed_headroom))
|
||||
WRITE_ONCE(dev->needed_headroom, headroom);
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
|
||||
mtu = min(tdev->mtu, IP_MAX_MTU);
|
||||
}
|
||||
|
||||
dev->needed_headroom = t_hlen + hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(t_hlen + hlen);
|
||||
mtu -= t_hlen + (dev->type == ARPHRD_ETHER ? dev->hard_header_len : 0);
|
||||
|
||||
if (mtu < IPV4_MIN_MTU)
|
||||
|
||||
@@ -1137,8 +1137,11 @@ static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
|
||||
return;
|
||||
|
||||
if (rt->dst.dev) {
|
||||
dev->needed_headroom = rt->dst.dev->hard_header_len +
|
||||
t_hlen;
|
||||
unsigned int headroom;
|
||||
|
||||
headroom = rt->dst.dev->hard_header_len + t_hlen;
|
||||
headroom = ip_tunnel_limit_headroom(headroom);
|
||||
dev->needed_headroom = headroom;
|
||||
|
||||
if (set_mtu) {
|
||||
int mtu = rt->dst.dev->mtu - t_hlen;
|
||||
|
||||
@@ -1514,8 +1514,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
|
||||
tdev = __dev_get_by_index(t->net, p->link);
|
||||
|
||||
if (tdev) {
|
||||
dev->needed_headroom = tdev->hard_header_len +
|
||||
tdev->needed_headroom + t_hlen;
|
||||
unsigned int headroom;
|
||||
|
||||
headroom = tdev->hard_header_len + tdev->needed_headroom;
|
||||
headroom += t_hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(headroom);
|
||||
mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU);
|
||||
|
||||
mtu = mtu - t_hlen;
|
||||
|
||||
@@ -1131,7 +1131,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev)
|
||||
WRITE_ONCE(dev->mtu, mtu);
|
||||
hlen = tdev->hard_header_len + tdev->needed_headroom;
|
||||
}
|
||||
dev->needed_headroom = t_hlen + hlen;
|
||||
dev->needed_headroom = ip_tunnel_limit_headroom(t_hlen + hlen);
|
||||
}
|
||||
|
||||
static void ipip6_tunnel_update(struct ip_tunnel *t,
|
||||
|
||||
Reference in New Issue
Block a user