• P
    ip6_gre: Fix skb_under_panic in __gre6_xmit() · ab198e1d
    Peilin Ye 提交于
    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: 6712abc1 ("ip6_gre: add ip6 gre and gretap collect_md mode")
    Reported-by: NFeng Zhou <zhoufeng.zf@bytedance.com>
    Co-developed-by: NCong Wang <cong.wang@bytedance.com>
    Signed-off-by: NCong Wang <cong.wang@bytedance.com>
    Signed-off-by: NPeilin Ye <peilin.ye@bytedance.com>
    Signed-off-by: NDavid S. Miller <davem@davemloft.net>
    ab198e1d
ip6_gre.c 58.4 KB