lkml.org 
[lkml]   [2022]   [Apr]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 249/343] bpf: Support dual-stack sockets in bpf_tcp_check_syncookie
    Date
    From: Maxim Mikityanskiy <maximmi@nvidia.com>

    [ Upstream commit 2e8702cc0cfa1080f29fd64003c00a3e24ac38de ]

    bpf_tcp_gen_syncookie looks at the IP version in the IP header and
    validates the address family of the socket. It supports IPv4 packets in
    AF_INET6 dual-stack sockets.

    On the other hand, bpf_tcp_check_syncookie looks only at the address
    family of the socket, ignoring the real IP version in headers, and
    validates only the packet size. This implementation has some drawbacks:

    1. Packets are not validated properly, allowing a BPF program to trick
    bpf_tcp_check_syncookie into handling an IPv6 packet on an IPv4
    socket.

    2. Dual-stack sockets fail the checks on IPv4 packets. IPv4 clients end
    up receiving a SYNACK with the cookie, but the following ACK gets
    dropped.

    This patch fixes these issues by changing the checks in
    bpf_tcp_check_syncookie to match the ones in bpf_tcp_gen_syncookie. IP
    version from the header is taken into account, and it is validated
    properly with address family.

    Fixes: 399040847084 ("bpf: add helper to check for a valid SYN cookie")
    Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
    Signed-off-by: Alexei Starovoitov <ast@kernel.org>
    Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
    Acked-by: Arthur Fabre <afabre@cloudflare.com>
    Link: https://lore.kernel.org/bpf/20220406124113.2795730-1-maximmi@nvidia.com
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/core/filter.c | 17 +++++++++++++----
    1 file changed, 13 insertions(+), 4 deletions(-)

    diff --git a/net/core/filter.c b/net/core/filter.c
    index 82fcb7533663..48fc95626597 100644
    --- a/net/core/filter.c
    +++ b/net/core/filter.c
    @@ -6777,24 +6777,33 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len
    if (!th->ack || th->rst || th->syn)
    return -ENOENT;

    + if (unlikely(iph_len < sizeof(struct iphdr)))
    + return -EINVAL;
    +
    if (tcp_synq_no_recent_overflow(sk))
    return -ENOENT;

    cookie = ntohl(th->ack_seq) - 1;

    - switch (sk->sk_family) {
    - case AF_INET:
    - if (unlikely(iph_len < sizeof(struct iphdr)))
    + /* Both struct iphdr and struct ipv6hdr have the version field at the
    + * same offset so we can cast to the shorter header (struct iphdr).
    + */
    + switch (((struct iphdr *)iph)->version) {
    + case 4:
    + if (sk->sk_family == AF_INET6 && ipv6_only_sock(sk))
    return -EINVAL;

    ret = __cookie_v4_check((struct iphdr *)iph, th, cookie);
    break;

    #if IS_BUILTIN(CONFIG_IPV6)
    - case AF_INET6:
    + case 6:
    if (unlikely(iph_len < sizeof(struct ipv6hdr)))
    return -EINVAL;

    + if (sk->sk_family != AF_INET6)
    + return -EINVAL;
    +
    ret = __cookie_v6_check((struct ipv6hdr *)iph, th, cookie);
    break;
    #endif /* CONFIG_IPV6 */
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-04-12 10:58    [W:3.233 / U:0.196 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site