• msizanoen1's avatar
    ipv6: fix memory leak in fib6_rule_suppress · cdef4852
    msizanoen1 authored
    The kernel leaks memory when a `fib` rule is present in IPv6 nftables
    firewall rules and a suppress_prefix rule is present in the IPv6 routing
    rules (used by certain tools such as wg-quick). In such scenarios, every
    incoming packet will leak an allocation in `ip6_dst_cache` slab cache.
    
    After some hours of `bpftrace`-ing and source code reading, I tracked
    down the issue to ca7a03c4 ("ipv6: do not free rt if
    FIB_LOOKUP_NOREF is set on suppress rule").
    
    The problem with that change is that the generic `args->flags` always have
    `FIB_LOOKUP_NOREF` set[1][2] but the IPv6-specific flag
    `RT6_LOOKUP_F_DST_NOREF` might not be, leading to `fib6_rule_suppress` not
    decreasing the refcount when needed.
    
    How to reproduce:
     - Add the following nftables rule to a prerouting chain:
         meta nfproto ipv6 fib saddr . mark . iif oif missing drop
       This can be done with:
         sudo nft create table inet test
         sudo nft create chain inet test test_chain '{ type filter hook prerouting priority filter + 10; policy accept; }'
         sudo nft add rule inet test test_chain meta nfproto ipv6 fib saddr . mark . iif oif missing drop
     - Run:
         sudo ip -6 rule add table main suppress_prefixlength 0
     - Watch `sudo slabtop -o | grep ip6_dst_cache` to see memory usage increase
       with every incoming ipv6 packet.
    
    This patch exposes the protocol-specific flags to the protocol
    specific `suppress` function, and check the protocol-specific `flags`
    argument for RT6_LOOKUP_F_DST_NOREF instead of the generic
    FIB_LOOKUP_NOREF when decreasing the refcount, like this.
    
    [1]: https://github.com/torvalds/linux/blob/ca7a03c4175366a92cee0ccc4fec0038c3266e26/net/ipv6/fib6_rules.c#L71
    [2]: https://github.com/torvalds/linux/blob/ca7a03c4175366a92cee0ccc4fec0038c3266e26/net/ipv6/fib6_rules.c#L99
    
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=215105
    Fixes: ca7a03c4 ("ipv6: do not free rt if FIB_LOOKUP_NOREF is set on suppress rule")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarJason A. Donenfeld <Jason@zx2c4.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    cdef4852
fib_rules.c 30.2 KB