ip6_gre: Fix skb_under_panic in __gre6_xmit()
Feng reported an skb_under_panic BUG triggered by running
test_ip6gretap() in tools/testing/selftests/bpf/test_tunnel.sh:
[ 82.492551] skbuff: skb_under_panic: text:ffffffffb268bb8e len:403 put:12 head:ffff9997c5480000 data:ffff9997c547fff8 tail:0x18b end:0x2c0 dev:ip6gretap11
<...>
[ 82.607380] Call Trace:
[ 82.609389] <TASK>
[ 82.611136] skb_push.cold.109+0x10/0x10
[ 82.614289] __gre6_xmit+0x41e/0x590
[ 82.617169] ip6gre_tunnel_xmit+0x344/0x3f0
[ 82.620526] dev_hard_start_xmit+0xf1/0x330
[ 82.623882] sch_direct_xmit+0xe4/0x250
[ 82.626961] __dev_queue_xmit+0x720/0xfe0
<...>
[ 82.633431] packet_sendmsg+0x96a/0x1cb0
[ 82.636568] sock_sendmsg+0x30/0x40
<...>
The following sequence of events caused the BUG:
1. During ip6gretap device initialization, tunnel->tun_hlen (e.g. 4) is
calculated based on old flags (see ip6gre_calc_hlen());
2. packet_snd() reserves header room for skb A, assuming
tunnel->tun_hlen is 4;
3. Later (in clsact Qdisc), the eBPF program sets a new tunnel key for
skb A using bpf_skb_set_tunnel_key() (see _ip6gretap_set_tunnel());
4. __gre6_xmit() detects the new tunnel key, and recalculates
"tun_hlen" (e.g. 12) based on new flags (e.g. TUNNEL_KEY and
TUNNEL_SEQ);
5. gre_build_header() calls skb_push() with insufficient reserved header
room, triggering the BUG.
As sugguested by Cong, fix it by moving the call to skb_cow_head() after
the recalculation of tun_hlen.
Reproducer:
OBJ=$LINUX/tools/testing/selftests/bpf/test_tunnel_kern.o
ip netns add at_ns0
ip link add veth0 type veth peer name veth1
ip link set veth0 netns at_ns0
ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
ip netns exec at_ns0 ip link set dev veth0 up
ip link set dev veth1 up mtu 1500
ip addr add dev veth1 172.16.1.200/24
ip netns exec at_ns0 ip addr add ::11/96 dev veth0
ip netns exec at_ns0 ip link set dev veth0 up
ip addr add dev veth1 ::22/96
ip link set dev veth1 up
ip netns exec at_ns0 \
ip link add dev ip6gretap00 type ip6gretap seq flowlabel 0xbcdef key 2 \
local ::11 remote ::22
ip netns exec at_ns0 ip addr add dev ip6gretap00 10.1.1.100/24
ip netns exec at_ns0 ip addr add dev ip6gretap00 fc80::100/96
ip netns exec at_ns0 ip link set dev ip6gretap00 up
ip link add dev ip6gretap11 type ip6gretap external
ip addr add dev ip6gretap11 10.1.1.200/24
ip addr add dev ip6gretap11 fc80::200/24
ip link set dev ip6gretap11 up
tc qdisc add dev ip6gretap11 clsact
tc filter add dev ip6gretap11 egress bpf da obj $OBJ sec ip6gretap_set_tunnel
tc filter add dev ip6gretap11 ingress bpf da obj $OBJ sec ip6gretap_get_tunnel
ping6 -c 3 -w 10 -q ::11
Fixes: 6712abc168
("ip6_gre: add ip6 gre and gretap collect_md mode")
Reported-by: Feng Zhou <zhoufeng.zf@bytedance.com>
Co-developed-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f40c064e93
commit
ab198e1d0d
|
@ -733,9 +733,6 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
|
||||||
else
|
else
|
||||||
fl6->daddr = tunnel->parms.raddr;
|
fl6->daddr = tunnel->parms.raddr;
|
||||||
|
|
||||||
if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Push GRE header. */
|
/* Push GRE header. */
|
||||||
protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
|
protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto;
|
||||||
|
|
||||||
|
@ -763,6 +760,9 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
|
||||||
(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
|
(TUNNEL_CSUM | TUNNEL_KEY | TUNNEL_SEQ);
|
||||||
tun_hlen = gre_calc_hlen(flags);
|
tun_hlen = gre_calc_hlen(flags);
|
||||||
|
|
||||||
|
if (skb_cow_head(skb, dev->needed_headroom ?: tun_hlen + tunnel->encap_hlen))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
gre_build_header(skb, tun_hlen,
|
gre_build_header(skb, tun_hlen,
|
||||||
flags, protocol,
|
flags, protocol,
|
||||||
tunnel_id_to_key32(tun_info->key.tun_id),
|
tunnel_id_to_key32(tun_info->key.tun_id),
|
||||||
|
@ -773,6 +773,9 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
|
||||||
if (tunnel->parms.o_flags & TUNNEL_SEQ)
|
if (tunnel->parms.o_flags & TUNNEL_SEQ)
|
||||||
tunnel->o_seqno++;
|
tunnel->o_seqno++;
|
||||||
|
|
||||||
|
if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
|
gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
|
||||||
protocol, tunnel->parms.o_key,
|
protocol, tunnel->parms.o_key,
|
||||||
htonl(tunnel->o_seqno));
|
htonl(tunnel->o_seqno));
|
||||||
|
|
Loading…
Reference in New Issue