lkml.org 
[lkml]   [2020]   [May]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 034/114] netfilter: nat: never update the UDP checksum when its 0
    Date
    From: Guillaume Nault <gnault@redhat.com>

    commit ea64d8d6c675c0bb712689b13810301de9d8f77a upstream.

    If the UDP header of a local VXLAN endpoint is NAT-ed, and the VXLAN
    device has disabled UDP checksums and enabled Tx checksum offloading,
    then the skb passed to udp_manip_pkt() has hdr->check == 0 (outer
    checksum disabled) and skb->ip_summed == CHECKSUM_PARTIAL (inner packet
    checksum offloaded).

    Because of the ->ip_summed value, udp_manip_pkt() tries to update the
    outer checksum with the new address and port, leading to an invalid
    checksum sent on the wire, as the original null checksum obviously
    didn't take the old address and port into account.

    So, we can't take ->ip_summed into account in udp_manip_pkt(), as it
    might not refer to the checksum we're acting on. Instead, we can base
    the decision to update the UDP checksum entirely on the value of
    hdr->check, because it's null if and only if checksum is disabled:

    * A fully computed checksum can't be 0, since a 0 checksum is
    represented by the CSUM_MANGLED_0 value instead.

    * A partial checksum can't be 0, since the pseudo-header always adds
    at least one non-zero value (the UDP protocol type 0x11) and adding
    more values to the sum can't make it wrap to 0 as the carry is then
    added to the wrapped number.

    * A disabled checksum uses the special value 0.

    The problem seems to be there from day one, although it was probably
    not visible before UDP tunnels were implemented.

    Fixes: 5b1158e909ec ("[NETFILTER]: Add NAT support for nf_conntrack")
    Signed-off-by: Guillaume Nault <gnault@redhat.com>
    Reviewed-by: Florian Westphal <fw@strlen.de>
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    net/netfilter/nf_nat_proto_udp.c | 5 ++---
    1 file changed, 2 insertions(+), 3 deletions(-)

    --- a/net/netfilter/nf_nat_proto_udp.c
    +++ b/net/netfilter/nf_nat_proto_udp.c
    @@ -66,15 +66,14 @@ static bool udp_manip_pkt(struct sk_buff
    enum nf_nat_manip_type maniptype)
    {
    struct udphdr *hdr;
    - bool do_csum;

    if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
    return false;

    hdr = (struct udphdr *)(skb->data + hdroff);
    - do_csum = hdr->check || skb->ip_summed == CHECKSUM_PARTIAL;
    + __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype,
    + !!hdr->check);

    - __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype, do_csum);
    return true;
    }


    \
     
     \ /
      Last update: 2020-05-18 19:47    [W:4.263 / U:0.168 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site