lkml.org 
[lkml]   [2022]   [Apr]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 037/124] ip6_gre: Fix skb_under_panic in __gre6_xmit()
    Date
    From: Peilin Ye <peilin.ye@bytedance.com>

    [ Upstream commit ab198e1d0dd8dc4bc7575fb50758e2cbd51e14e1 ]

    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: 6712abc168eb ("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>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/ipv6/ip6_gre.c | 9 ++++++---
    1 file changed, 6 insertions(+), 3 deletions(-)

    diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
    index 288720838329..869c3337e319 100644
    --- a/net/ipv6/ip6_gre.c
    +++ b/net/ipv6/ip6_gre.c
    @@ -733,9 +733,6 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
    else
    fl6->daddr = tunnel->parms.raddr;

    - if (skb_cow_head(skb, dev->needed_headroom ?: tunnel->hlen))
    - return -ENOMEM;
    -
    /* Push GRE header. */
    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);
    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,
    flags, protocol,
    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)
    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,
    protocol, tunnel->parms.o_key,
    htonl(tunnel->o_seqno));
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-04-26 11:14    [W:4.095 / U:0.356 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site