From nobody Fri Jun 12 13:55:44 2026 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A5AF29E11A for ; Mon, 8 Jun 2026 12:59:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780923558; cv=none; b=HhaBZdVSfw3cUjDR+2Ye7PqC0PYZk0ApWhwjz68VKbhay9+VnkP2Jr02qFP7n9FiXDb+fNm7Zfr06vtl4Ru5Mnn9jc+oVyVlJvx/O3JfJ8DbShOCIg2k8ozJKvpZTIZHVk35EpGpxJdorMK01vEM7Cvpnp7M9dj/ysp9+AoS4dQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780923558; c=relaxed/simple; bh=TGqy07e0KYWbqiUT34j9FgI4+mqzg0Sk7pj9Hp1mx78=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sSQf1VL5Dcu5ZKURekhqTPPozOkjzi9RzV4IaS+uIjLkQnjdpBx2Wi1mVOiVVp1XjDHj5KWyBwloLjWmg0jvmYhvEUxRCEKZvlrPaVkCMOkn1RuM7EsrtJnkNLjrUfyOrw4Op7Wyc82pZd7oRifMWzMeveMQCGRbYmbM2CeQREY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=CkYmGqRA; arc=none smtp.client-ip=91.218.175.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="CkYmGqRA" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1780923555; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/z9lruv/1Ak6FgR3qictfE2wiKZjsqaHqmY33SqWS/c=; b=CkYmGqRA5zperjGEMNE9HW8CqVdhDBCq1zGzFLJLqt/tJiOTzkyvquzaYie+4468oMEEWt jb0Dgn5K4ttBntNblWwlvirAjKP8zOA8NVmUsdpQiv1vBxceKAoGirq5sC+STcQDP5H7+Y 9J7TXZq4Yq2tgDxU6Kw9GIsyqLPe7bI= From: Jiayuan Chen To: bpf@vger.kernel.org Cc: Jiayuan Chen , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Willem de Bruijn , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman , Kumar Kartikeya Dwivedi , Song Liu , Yonghong Song , Jiri Olsa , Shuah Khan , Joe Stringer , Kuniyuki Iwashima , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf v8 1/2] net: Validate protocol in skb_steal_sock() for BPF-assigned sockets Date: Mon, 8 Jun 2026 20:58:27 +0800 Message-ID: <20260608125846.157004-2-jiayuan.chen@linux.dev> In-Reply-To: <20260608125846.157004-1-jiayuan.chen@linux.dev> References: <20260608125846.157004-1-jiayuan.chen@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT bpf_sk_assign_tcp_reqsk() can assign a TCP reqsk to a non-TCP skb, causing a panic when the skb enters the wrong L4 receive path [1]. An initial attempt tried to fix this in the BPF helper by checking iph->protocol, but Sashiko [2] revealed that BPF programs can bypass this check via a TOCTOU attack by modifying iph->protocol around the call: iph->protocol =3D IPPROTO_TCP; bpf_sk_assign_tcp_reqsk(udp_skb, tcp_sk); iph->protocol =3D IPPROTO_UDP; Furthermore, bpf_sk_assign() has had the same class of vulnerability since its introduction =E2=80=94 it can assign any socket type to any skb without protocol validation. Since the BPF helper check alone cannot prevent a malicious BPF program from crashing the kernel, add protocol validation in skb_steal_sock() to reject mismatched sockets regardless of how they were assigned. The check is applied to all prefetched sockets. Early demux paths already only assign matching protocols (e.g., UDP early demux only assigns UDP sockets to UDP skbs), so they pass the check naturally and the extra branch is negligible. Pass the expected protocol from callers rather than extracting it from the IP header. For IPv6, walking extension headers to find the L4 protocol is complex and unnecessary since each caller already knows the protocol it handles. [1] https://lore.kernel.org/bpf/20260403015851.148209-1-jiayuan.chen@linux.= dev/ [2] https://sashiko.dev/#/patchset/20260403015851.148209-1-jiayuan.chen%40l= inux.dev Fixes: cf7fbe660f2d ("bpf: Add socket assign support") Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.") Signed-off-by: Jiayuan Chen --- include/net/inet6_hashtables.h | 7 ++++--- include/net/inet_hashtables.h | 7 ++++--- include/net/request_sock.h | 16 +++++++++++++++- net/ipv4/udp.c | 2 +- net/ipv6/udp.c | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index 2cc5d416bbb5a..218498373a9c1 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h @@ -106,12 +106,13 @@ static inline struct sock *inet6_steal_sock(struct net *net, struct sk_buff *skb, int do= ff, const struct in6_addr *saddr, const __be16 sport, const struct in6_addr *daddr, const __be16 dport, - bool *refcounted, inet6_ehashfn_t *ehashfn) + bool *refcounted, inet6_ehashfn_t *ehashfn, + int protocol) { struct sock *sk, *reuse_sk; bool prefetched; =20 - sk =3D skb_steal_sock(skb, refcounted, &prefetched); + sk =3D skb_steal_sock(skb, refcounted, &prefetched, protocol); if (!sk) return NULL; =20 @@ -153,7 +154,7 @@ static inline struct sock *__inet6_lookup_skb(struct sk= _buff *skb, int doff, struct sock *sk; =20 sk =3D inet6_steal_sock(net, skb, doff, &ip6h->saddr, sport, &ip6h->daddr= , dport, - refcounted, inet6_ehashfn); + refcounted, inet6_ehashfn, IPPROTO_TCP); if (IS_ERR(sk)) return NULL; if (sk) diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 6e2fe186d0dcb..a2a044f93cc4b 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -446,12 +446,13 @@ static inline struct sock *inet_steal_sock(struct net *net, struct sk_buff *skb, int dof= f, const __be32 saddr, const __be16 sport, const __be32 daddr, const __be16 dport, - bool *refcounted, inet_ehashfn_t *ehashfn) + bool *refcounted, inet_ehashfn_t *ehashfn, + int protocol) { struct sock *sk, *reuse_sk; bool prefetched; =20 - sk =3D skb_steal_sock(skb, refcounted, &prefetched); + sk =3D skb_steal_sock(skb, refcounted, &prefetched, protocol); if (!sk) return NULL; =20 @@ -494,7 +495,7 @@ static inline struct sock *__inet_lookup_skb(struct sk_= buff *skb, struct sock *sk; =20 sk =3D inet_steal_sock(net, skb, doff, iph->saddr, sport, iph->daddr, dpo= rt, - refcounted, inet_ehashfn); + refcounted, inet_ehashfn, IPPROTO_TCP); if (IS_ERR(sk)) return NULL; if (sk) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 5a9c826a7092d..c2b8c6350b624 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -89,9 +89,11 @@ static inline struct sock *req_to_sk(struct request_sock= *req) * @skb: sk_buff to steal the socket from * @refcounted: is set to true if the socket is reference-counted * @prefetched: is set to true if the socket was assigned from bpf + * @protocol: expected L4 protocol */ static inline struct sock *skb_steal_sock(struct sk_buff *skb, - bool *refcounted, bool *prefetched) + bool *refcounted, bool *prefetched, + int protocol) { struct sock *sk =3D skb->sk; =20 @@ -103,6 +105,18 @@ static inline struct sock *skb_steal_sock(struct sk_bu= ff *skb, =20 *prefetched =3D skb_sk_is_prefetched(skb); if (*prefetched) { + /* A non-full socket here is either a reqsk or a + * timewait sock, both only contain sock_common and + * lack sk_protocol. Since both can only be TCP, + * use IPPROTO_TCP as the protocol. + */ + if (unlikely(((sk_fullsock(sk) ? sk->sk_protocol : IPPROTO_TCP) !=3D pro= tocol))) { + skb_orphan(skb); + *prefetched =3D false; + *refcounted =3D false; + return NULL; + } + #if IS_ENABLED(CONFIG_SYN_COOKIES) if (sk->sk_state =3D=3D TCP_NEW_SYN_RECV && inet_reqsk(sk)->syncookie) { struct request_sock *req =3D inet_reqsk(sk); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0ac2bf4f8759b..ceb4d29a64aca 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2618,7 +2618,7 @@ int udp_rcv(struct sk_buff *skb) goto csum_error; =20 sk =3D inet_steal_sock(net, skb, sizeof(struct udphdr), saddr, uh->source= , daddr, uh->dest, - &refcounted, udp_ehashfn); + &refcounted, udp_ehashfn, IPPROTO_UDP); if (IS_ERR(sk)) goto no_sk; =20 diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 15e032194eccc..d9c12cce5acef 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1106,7 +1106,7 @@ INDIRECT_CALLABLE_SCOPE int udpv6_rcv(struct sk_buff = *skb) =20 /* Check if the socket is already available, e.g. due to early demux */ sk =3D inet6_steal_sock(net, skb, sizeof(struct udphdr), saddr, uh->sourc= e, daddr, uh->dest, - &refcounted, udp6_ehashfn); + &refcounted, udp6_ehashfn, IPPROTO_UDP); if (IS_ERR(sk)) goto no_sk; =20 --=20 2.43.0 From nobody Fri Jun 12 13:55:44 2026 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 493F029DB86 for ; Mon, 8 Jun 2026 12:59:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780923570; cv=none; b=Q4+Z8OFOTXXYMX+0DCA1KgZzEXWYOT0aGsfuHnoLsJ6lI5KEH8MSjFucBrl5ubJVRSOjuwYDNXqSHiiVCmz6e5tj+fwJCuUJMZtByXhJ3EfQRNqycjtPHuMFH2ZjnL/p4KOkIoj6EWOnZ1gaJ2iM98UCpXCTXscSFvjNw+3OZKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780923570; c=relaxed/simple; bh=pppSCiti4jvi5EsxxegmSDnZrha/rHxM9F+JK/EvxDU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=k5vA5JRpyo2TxXOLbNVwAeMQukdh8z5GcrewqEzzkhGM/2c+1qYB1Z4XXquQUOIr0PuNs6W3dv4Fes6JOvV9BvgHE8mAa+eVmRBdnnVe9Bw59DScP3BWTZT6h+T509wvv58Sillxzfz7rPM5wAMzHK98cNrk5g5byOmc8YDCkGM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=FHYQcl/j; arc=none smtp.client-ip=91.218.175.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="FHYQcl/j" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1780923566; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=k3XNGhcQHJVmcyavdjn9EhDX/kEW3MIT6FKFuaZuhMc=; b=FHYQcl/jKZ6FER/I7Nsw0rubDgjwRebm9faiJzCI6Qy+D8pGv+GbpsYyyaMA55ERV5fNNp otTEdJUoB4CTR2WhYFXTqtOWwbmMlOHux0E0n4s3X5YKNLzplzDmAwIwYJtk6UlEz/Yi4n ogIVPOzzs4Q498mo8pFRzuuYhHCq0lA= From: Jiayuan Chen To: bpf@vger.kernel.org Cc: Jiayuan Chen , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Willem de Bruijn , Andrii Nakryiko , Eduard Zingerman , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Kumar Kartikeya Dwivedi , Song Liu , Yonghong Song , Jiri Olsa , Shuah Khan , Joe Stringer , Kuniyuki Iwashima , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH bpf v8 2/2] selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk() Date: Mon, 8 Jun 2026 20:58:28 +0800 Message-ID: <20260608125846.157004-3-jiayuan.chen@linux.dev> In-Reply-To: <20260608125846.157004-1-jiayuan.chen@linux.dev> References: <20260608125846.157004-1-jiayuan.chen@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Add test_tcp_custom_syncookie_protocol_check to test assigning a TCP sk to UDP skb->sk. The test sends a UDP packet through TC ingress, where a BPF program calls bpf_sk_assign_tcp_reqsk() on it. A UDP server's recv() is used for synchronization to ensure the BPF program has finished processing before checking the result. Without the fix in bpf_sk_assign_tcp_reqsk(), this will cause a null pointer dereference panic when the kernel processes it through the UDP receive path. Test result: ./test_progs -a tcp_custom_syncookie_protocol_check -v setup_netns:PASS:create netns 0 nsec setup_netns:PASS:ip 0 nsec write_sysctl:PASS:open sysctl 0 nsec write_sysctl:PASS:write sysctl 0 nsec setup_netns:PASS:write_sysctl 0 nsec test_tcp_custom_syncookie_protocol_check:PASS:open_and_load 0 nsec setup_tc:PASS:qdisc add dev lo clsact 0 nsec setup_tc:PASS:filter add dev lo ingress 0 nsec run_protocol_check:PASS:start tcp_server 0 nsec run_protocol_check:PASS:start udp_server 0 nsec run_protocol_check:PASS:connect udp_client 0 nsec run_protocol_check:PASS:send udp 0 nsec run_protocol_check:PASS:recv udp 0 nsec run_protocol_check:PASS:recv data 0 nsec run_protocol_check:PASS:udp_intercepted 0 nsec #492/1 tcp_custom_syncookie_protocol_check/IPv4 TCP:OK run_protocol_check:PASS:start tcp_server 0 nsec run_protocol_check:PASS:start udp_server 0 nsec run_protocol_check:PASS:connect udp_client 0 nsec run_protocol_check:PASS:send udp 0 nsec run_protocol_check:PASS:recv udp 0 nsec run_protocol_check:PASS:recv data 0 nsec run_protocol_check:PASS:udp_intercepted 0 nsec #492/2 tcp_custom_syncookie_protocol_check/IPv6 TCP:OK #492 tcp_custom_syncookie_protocol_check:OK Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Jiayuan Chen --- .../bpf/prog_tests/tcp_custom_syncookie.c | 87 ++++++++++++++- .../bpf/progs/test_tcp_custom_syncookie.c | 102 ++++++++++++++++++ 2 files changed, 185 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c = b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c index 00d5c32674fc9..03103b7b9c5bf 100644 --- a/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c +++ b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c @@ -5,6 +5,7 @@ #include #include #include +#include =20 #include "test_progs.h" #include "cgroup_helpers.h" @@ -47,11 +48,10 @@ static int setup_netns(void) return -1; } =20 -static int setup_tc(struct test_tcp_custom_syncookie *skel) +static int setup_tc(int prog_fd) { LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point =3D BPF_TC_INGRESS); - LIBBPF_OPTS(bpf_tc_opts, tc_attach, - .prog_fd =3D bpf_program__fd(skel->progs.tcp_custom_syncookie)); + LIBBPF_OPTS(bpf_tc_opts, tc_attach, .prog_fd =3D prog_fd); =20 qdisc_lo.ifindex =3D if_nametoindex("lo"); if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact")) @@ -147,7 +147,7 @@ void test_tcp_custom_syncookie(void) if (!ASSERT_OK_PTR(skel, "open_and_load")) return; =20 - if (setup_tc(skel)) + if (setup_tc(bpf_program__fd(skel->progs.tcp_custom_syncookie))) goto destroy_skel; =20 for (i =3D 0; i < ARRAY_SIZE(test_cases); i++) { @@ -165,6 +165,85 @@ void test_tcp_custom_syncookie(void) =20 destroy_skel: system("tc qdisc del dev lo clsact"); + test_tcp_custom_syncookie__destroy(skel); +} + +/* TCP and UDP servers share the same port. The BPF program intercepts + * the UDP packet, looks up the TCP listener via the dest port, and + * attempts to assign a TCP reqsk to the UDP skb. + * Although bpf_sk_assign_tcp_reqsk() assign udp skb to tcp reqsk, the + * network stack should not crash. + */ +static void run_protocol_check(struct test_tcp_custom_syncookie *skel, + int family, const char *addr) +{ + int tcp_server, udp_server, udp_client; + char buf[] =3D "test"; + int port, ret; + + tcp_server =3D start_server(family, SOCK_STREAM, addr, 0, 0); + if (!ASSERT_NEQ(tcp_server, -1, "start tcp_server")) + return; + + port =3D ntohs(get_socket_local_port(tcp_server)); + + /* UDP server on same port for synchronization and port sharing */ + udp_server =3D start_server(family, SOCK_DGRAM, addr, port, 0); + if (!ASSERT_NEQ(udp_server, -1, "start udp_server")) + goto close_tcp; + + skel->bss->udp_intercepted =3D false; + + udp_client =3D connect_to_fd(udp_server, 0); + if (!ASSERT_NEQ(udp_client, -1, "connect udp_client")) + goto close_udp_server; + + ret =3D send(udp_client, buf, sizeof(buf), 0); + if (!ASSERT_EQ(ret, sizeof(buf), "send udp")) + goto close_udp_client; + + memset(buf, 0, sizeof(buf)); + + /* recv() ensures TC ingress BPF has processed the skb */ + ret =3D recv(udp_server, buf, sizeof(buf), 0); + if (!ASSERT_EQ(ret, sizeof(buf), "recv udp")) + goto close_udp_client; + + ASSERT_STREQ(buf, "test", "recv data"); + ASSERT_EQ(skel->bss->udp_intercepted, true, "udp_intercepted"); + +close_udp_client: + close(udp_client); +close_udp_server: + close(udp_server); +close_tcp: + close(tcp_server); +} + +void test_tcp_custom_syncookie_protocol_check(void) +{ + struct test_tcp_custom_syncookie *skel; + int i; + + if (setup_netns()) + return; =20 + skel =3D test_tcp_custom_syncookie__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + if (setup_tc(bpf_program__fd(skel->progs.tcp_custom_syncookie_badproto))) + goto destroy_skel; + + for (i =3D 0; i < ARRAY_SIZE(test_cases); i++) { + if (!test__start_subtest(test_cases[i].name)) + continue; + + run_protocol_check(skel, test_cases[i].family, + test_cases[i].addr); + } + +destroy_skel: + system("tc qdisc del dev lo clsact"); test_tcp_custom_syncookie__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c = b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c index 7d5293de19523..5cf99d2a12aa5 100644 --- a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c +++ b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c @@ -588,4 +588,106 @@ int tcp_custom_syncookie(struct __sk_buff *skb) return tcp_handle_ack(&ctx); } =20 +/* Test: call bpf_sk_assign_tcp_reqsk() on a UDP skb. */ +bool udp_intercepted; + +static int badproto_lookup_assign(struct __sk_buff *skb, + struct bpf_sock_tuple *tuple, u32 tuple_size) +{ + struct bpf_tcp_req_attrs attrs =3D {}; + struct bpf_sock *skc; + struct sock *sk; + + skc =3D bpf_skc_lookup_tcp(skb, tuple, tuple_size, -1, 0); + if (!skc) + return TC_ACT_OK; + + if (skc->state !=3D TCP_LISTEN) { + bpf_sk_release(skc); + return TC_ACT_OK; + } + + sk =3D (struct sock *)bpf_skc_to_tcp_sock(skc); + if (!sk) { + bpf_sk_release(skc); + return TC_ACT_OK; + } + + attrs.mss =3D 1460; + attrs.wscale_ok =3D 1; + attrs.snd_wscale =3D 7; + attrs.rcv_wscale =3D 7; + attrs.sack_ok =3D 1; + + bpf_sk_assign_tcp_reqsk(skb, sk, &attrs, sizeof(attrs)); + + bpf_sk_release(skc); + return TC_ACT_OK; +} + +SEC("tc") +int tcp_custom_syncookie_badproto(struct __sk_buff *skb) +{ + void *data =3D (void *)(long)skb->data; + void *data_end =3D (void *)(long)skb->data_end; + struct bpf_sock_tuple tuple =3D {}; + struct ethhdr *eth; + struct iphdr *iph; + struct ipv6hdr *ip6h; + struct udphdr *udp; + + eth =3D (struct ethhdr *)data; + if (eth + 1 > data_end) + return TC_ACT_OK; + + switch (bpf_ntohs(eth->h_proto)) { + case ETH_P_IP: + iph =3D (struct iphdr *)(eth + 1); + if (iph + 1 > data_end) + return TC_ACT_OK; + + if (iph->protocol !=3D IPPROTO_UDP) + return TC_ACT_OK; + + udp =3D (struct udphdr *)(iph + 1); + if (udp + 1 > data_end) + return TC_ACT_OK; + + udp_intercepted =3D true; + + tuple.ipv4.saddr =3D iph->saddr; + tuple.ipv4.daddr =3D iph->daddr; + tuple.ipv4.sport =3D udp->source; + tuple.ipv4.dport =3D udp->dest; + + return badproto_lookup_assign(skb, &tuple, + sizeof(tuple.ipv4)); + case ETH_P_IPV6: + ip6h =3D (struct ipv6hdr *)(eth + 1); + if (ip6h + 1 > data_end) + return TC_ACT_OK; + + if (ip6h->nexthdr !=3D IPPROTO_UDP) + return TC_ACT_OK; + + udp =3D (struct udphdr *)(ip6h + 1); + if (udp + 1 > data_end) + return TC_ACT_OK; + + udp_intercepted =3D true; + + __builtin_memcpy(tuple.ipv6.saddr, &ip6h->saddr, + sizeof(tuple.ipv6.saddr)); + __builtin_memcpy(tuple.ipv6.daddr, &ip6h->daddr, + sizeof(tuple.ipv6.daddr)); + tuple.ipv6.sport =3D udp->source; + tuple.ipv6.dport =3D udp->dest; + + return badproto_lookup_assign(skb, &tuple, + sizeof(tuple.ipv6)); + default: + return TC_ACT_OK; + } +} + char _license[] SEC("license") =3D "GPL"; --=20 2.43.0