lkml.org 
[lkml]   [2021]   [Jul]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.12 026/160] bpf: Check for BPF_F_ADJ_ROOM_FIXED_GSO when bpf_skb_change_proto
    Date
    From: Dongseok Yi <dseok.yi@samsung.com>

    [ Upstream commit fa7b83bf3b156c767f3e4a25bbf3817b08f3ff8e ]

    In the forwarding path GRO -> BPF 6 to 4 -> GSO for TCP traffic, the
    coalesced packet payload can be > MSS, but < MSS + 20.

    bpf_skb_proto_6_to_4() will upgrade the MSS and it can be > the payload
    length. After then tcp_gso_segment checks for the payload length if it
    is <= MSS. The condition is causing the packet to be dropped.

    tcp_gso_segment():
    [...]
    mss = skb_shinfo(skb)->gso_size;
    if (unlikely(skb->len <= mss))
    goto out;
    [...]

    Allow to upgrade/downgrade MSS only when BPF_F_ADJ_ROOM_FIXED_GSO is
    not set.

    Signed-off-by: Dongseok Yi <dseok.yi@samsung.com>
    Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
    Acked-by: Willem de Bruijn <willemb@google.com>
    Link: https://lore.kernel.org/bpf/1620804453-57566-1-git-send-email-dseok.yi@samsung.com
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/core/filter.c | 22 +++++++++++++---------
    1 file changed, 13 insertions(+), 9 deletions(-)

    diff --git a/net/core/filter.c b/net/core/filter.c
    index 52f4359efbd2..849b08350a39 100644
    --- a/net/core/filter.c
    +++ b/net/core/filter.c
    @@ -3238,7 +3238,7 @@ static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len)
    return ret;
    }

    -static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
    +static int bpf_skb_proto_4_to_6(struct sk_buff *skb, u64 flags)
    {
    const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
    u32 off = skb_mac_header_len(skb);
    @@ -3267,7 +3267,9 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
    }

    /* Due to IPv6 header, MSS needs to be downgraded. */
    - skb_decrease_gso_size(shinfo, len_diff);
    + if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO))
    + skb_decrease_gso_size(shinfo, len_diff);
    +
    /* Header must be checked, and gso_segs recomputed. */
    shinfo->gso_type |= SKB_GSO_DODGY;
    shinfo->gso_segs = 0;
    @@ -3279,7 +3281,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
    return 0;
    }

    -static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
    +static int bpf_skb_proto_6_to_4(struct sk_buff *skb, u64 flags)
    {
    const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr);
    u32 off = skb_mac_header_len(skb);
    @@ -3308,7 +3310,9 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
    }

    /* Due to IPv4 header, MSS can be upgraded. */
    - skb_increase_gso_size(shinfo, len_diff);
    + if (!(flags & BPF_F_ADJ_ROOM_FIXED_GSO))
    + skb_increase_gso_size(shinfo, len_diff);
    +
    /* Header must be checked, and gso_segs recomputed. */
    shinfo->gso_type |= SKB_GSO_DODGY;
    shinfo->gso_segs = 0;
    @@ -3320,17 +3324,17 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
    return 0;
    }

    -static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto)
    +static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto, u64 flags)
    {
    __be16 from_proto = skb->protocol;

    if (from_proto == htons(ETH_P_IP) &&
    to_proto == htons(ETH_P_IPV6))
    - return bpf_skb_proto_4_to_6(skb);
    + return bpf_skb_proto_4_to_6(skb, flags);

    if (from_proto == htons(ETH_P_IPV6) &&
    to_proto == htons(ETH_P_IP))
    - return bpf_skb_proto_6_to_4(skb);
    + return bpf_skb_proto_6_to_4(skb, flags);

    return -ENOTSUPP;
    }
    @@ -3340,7 +3344,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
    {
    int ret;

    - if (unlikely(flags))
    + if (unlikely(flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO)))
    return -EINVAL;

    /* General idea is that this helper does the basic groundwork
    @@ -3360,7 +3364,7 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
    * that. For offloads, we mark packet as dodgy, so that headers
    * need to be verified first.
    */
    - ret = bpf_skb_proto_xlat(skb, proto);
    + ret = bpf_skb_proto_xlat(skb, proto, flags);
    bpf_compute_data_pointers(skb);
    return ret;
    }
    --
    2.30.2
    \
     
     \ /
      Last update: 2021-07-06 13:32    [W:4.106 / U:0.068 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site