From: Kuniyuki Iwashima <kuniyu@amazon.com>
To: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
David Ahern <dsahern@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
John Fastabend <john.fastabend@gmail.com>,
KP Singh <kpsingh@kernel.org>,
Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
Jiri Olsa <jolsa@kernel.org>, Mykola Lysenko <mykolal@fb.com>
Cc: Kuniyuki Iwashima <kuniyu@amazon.com>,
Kuniyuki Iwashima <kuni1840@gmail.com>, <bpf@vger.kernel.org>,
<netdev@vger.kernel.org>
Subject: [PATCH v1 bpf-next 11/11] selftest: bpf: Test BPF_SOCK_OPS_(GEN|CHECK)_SYNCOOKIE_CB.
Date: Fri, 13 Oct 2023 15:04:33 -0700 [thread overview]
Message-ID: <20231013220433.70792-12-kuniyu@amazon.com> (raw)
In-Reply-To: <20231013220433.70792-1-kuniyu@amazon.com>
This patch adds a test for BPF_SOCK_OPS_(GEN|CHECK)_SYNCOOKIE_CB hooks.
BPF_SOCK_OPS_GEN_SYNCOOKIE_CB hook generates a hash using SipHash from
based on 4-tuple. The hash is split into ISN and TS. MSS, ECN, SACK,
and WScale are encoded into the lower 8-bits of ISN.
ISN:
MSB LSB
| 31 ... 8 | 7 6 | 5 | 4 | 3 2 1 0 |
| Hash_1 | MSS | ECN | SACK | WScale |
TS:
MSB LSB
| 31 ... 8 | 7 ... 0 |
| Random | Hash_2 |
BPF_SOCK_OPS_CHECK_SYNCOOKIE_CB hook re-calculates the hash and validates
the cookie.
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
Currently, the validator is incomplete...
If this line is changed
skops->replylong[0] = msstab[3];
to
skops->replylong[0] = msstab[mssind];
, we will get the error below during make:
GEN-SKEL [test_progs] test_tcp_syncookie.skel.h
...
Error: failed to open BPF object file: No such file or directory
GEN-SKEL [test_progs-no_alu32] test_tcp_syncookie.skel.h
make: *** [Makefile:603: /home/ec2-user/kernel/bpf_syncookie/tools/testing/selftests/bpf/test_tcp_syncookie.skel.h] Error 254
make: *** Deleting file '/home/ec2-user/kernel/bpf_syncookie/tools/testing/selftests/bpf/test_tcp_syncookie.skel.h'
make: *** Waiting for unfinished jobs....
---
.../selftests/bpf/prog_tests/tcp_syncookie.c | 84 +++++++++
.../selftests/bpf/progs/test_siphash.h | 65 +++++++
.../selftests/bpf/progs/test_tcp_syncookie.c | 170 ++++++++++++++++++
.../selftests/bpf/test_tcp_hdr_options.h | 8 +-
4 files changed, 326 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/tcp_syncookie.c
create mode 100644 tools/testing/selftests/bpf/progs/test_siphash.h
create mode 100644 tools/testing/selftests/bpf/progs/test_tcp_syncookie.c
diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_syncookie.c b/tools/testing/selftests/bpf/prog_tests/tcp_syncookie.c
new file mode 100644
index 000000000000..53af1434fc2c
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/tcp_syncookie.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates. */
+
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdlib.h>
+
+#include "test_progs.h"
+#include "cgroup_helpers.h"
+#include "network_helpers.h"
+#include "test_tcp_syncookie.skel.h"
+
+static int setup_netns(void)
+{
+ if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
+ return -1;
+
+ if (!ASSERT_OK(system("ip link set dev lo up"), "system"))
+ return -1;
+
+ if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"),
+ "write_sysctl(tcp_syncookies)"))
+ return -1;
+
+ if (!ASSERT_OK(write_sysctl("/proc/sys/net/ipv4/tcp_ecn", "1"),
+ "write_sysctl(tcp_ecn)"))
+ return -1;
+
+ return 0;
+}
+
+static void create_connection(void)
+{
+ int server, client, child;
+
+ server = start_server(AF_INET, SOCK_STREAM, "127.0.0.1", 0, 0);
+ if (!ASSERT_NEQ(server, -1, "start_server"))
+ return;
+
+ client = connect_to_fd(server, 0);
+ if (!ASSERT_NEQ(client, -1, "connect_to_fd"))
+ goto close_server;
+
+ child = accept(server, NULL, 0);
+ if (!ASSERT_NEQ(child, -1, "accept"))
+ goto close_client;
+
+ close(child);
+close_client:
+ close(client);
+close_server:
+ close(server);
+}
+
+void test_tcp_syncookie(void)
+{
+ struct test_tcp_syncookie *skel;
+ struct bpf_link *link;
+ int cgroup;
+
+ if (setup_netns())
+ return;
+
+ skel = test_tcp_syncookie__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "open_and_load"))
+ return;
+
+ cgroup = test__join_cgroup("/tcp_syncookie");
+ if (!ASSERT_GE(cgroup, 0, "join_cgroup"))
+ goto destroy_skel;
+
+ link = bpf_program__attach_cgroup(skel->progs.syncookie, cgroup);
+ if (!ASSERT_OK_PTR(link, "attach_cgroup"))
+ goto close_cgroup;
+
+ create_connection();
+
+ bpf_link__destroy(link);
+
+close_cgroup:
+ close(cgroup);
+destroy_skel:
+ test_tcp_syncookie__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_siphash.h b/tools/testing/selftests/bpf/progs/test_siphash.h
new file mode 100644
index 000000000000..e36de63fdbaa
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_siphash.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates. */
+
+/* include/linux/bitops.h */
+static __always_inline __u64 rol64(__u64 word, unsigned int shift)
+{
+ return (word << (shift & 63)) | (word >> ((-shift) & 63));
+}
+
+/* include/linux/siphash.h */
+typedef struct {
+ __u64 key[2];
+} siphash_key_t;
+
+#define SIPHASH_PERMUTATION(a, b, c, d) ( \
+ (a) += (b), (b) = rol64((b), 13), (b) ^= (a), (a) = rol64((a), 32), \
+ (c) += (d), (d) = rol64((d), 16), (d) ^= (c), \
+ (a) += (d), (d) = rol64((d), 21), (d) ^= (a), \
+ (c) += (b), (b) = rol64((b), 17), (b) ^= (c), (c) = rol64((c), 32))
+
+#define SIPHASH_CONST_0 0x736f6d6570736575ULL
+#define SIPHASH_CONST_1 0x646f72616e646f6dULL
+#define SIPHASH_CONST_2 0x6c7967656e657261ULL
+#define SIPHASH_CONST_3 0x7465646279746573ULL
+
+/* lib/siphash.c */
+#define SIPROUND SIPHASH_PERMUTATION(v0, v1, v2, v3)
+
+#define PREAMBLE(len) \
+ __u64 v0 = SIPHASH_CONST_0; \
+ __u64 v1 = SIPHASH_CONST_1; \
+ __u64 v2 = SIPHASH_CONST_2; \
+ __u64 v3 = SIPHASH_CONST_3; \
+ __u64 b = ((__u64)(len)) << 56; \
+ v3 ^= key->key[1]; \
+ v2 ^= key->key[0]; \
+ v1 ^= key->key[1]; \
+ v0 ^= key->key[0];
+
+#define POSTAMBLE \
+ v3 ^= b; \
+ SIPROUND; \
+ SIPROUND; \
+ v0 ^= b; \
+ v2 ^= 0xff; \
+ SIPROUND; \
+ SIPROUND; \
+ SIPROUND; \
+ SIPROUND; \
+ return (v0 ^ v1) ^ (v2 ^ v3);
+
+static __always_inline __u64 siphash_2u64(const __u64 first, const __u64 second,
+ const siphash_key_t *key)
+{
+ PREAMBLE(16)
+ v3 ^= first;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= first;
+ v3 ^= second;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= second;
+ POSTAMBLE
+}
diff --git a/tools/testing/selftests/bpf/progs/test_tcp_syncookie.c b/tools/testing/selftests/bpf/progs/test_tcp_syncookie.c
new file mode 100644
index 000000000000..5d1fc928602b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_tcp_syncookie.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates. */
+
+#include <stdbool.h>
+#include <linux/bpf.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <bpf/bpf_helpers.h>
+#define BPF_PROG_TEST_TCP_HDR_OPTIONS
+#include "test_tcp_hdr_options.h"
+#include "test_siphash.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static int assert_gen_syncookie_cb(struct bpf_sock_ops *skops)
+{
+ struct tcp_opt tcp_opt;
+ int ret;
+
+ tcp_opt.kind = TCPOPT_WINDOW;
+ tcp_opt.len = 0;
+
+ ret = bpf_load_hdr_opt(skops, &tcp_opt, TCPOLEN_WINDOW, 0);
+ if (ret != TCPOLEN_WINDOW ||
+ tcp_opt.data[0] != (skops->args[1] & BPF_SYNCOOKIE_WSCALE_MASK))
+ goto err;
+
+ tcp_opt.kind = TCPOPT_SACK_PERM;
+ tcp_opt.len = 0;
+
+ ret = bpf_load_hdr_opt(skops, &tcp_opt, TCPOLEN_SACK_PERM, 0);
+ if (ret != TCPOLEN_SACK_PERM ||
+ !(skops->args[1] & BPF_SYNCOOKIE_SACK))
+ goto err;
+
+ tcp_opt.kind = TCPOPT_TIMESTAMP;
+ tcp_opt.len = 0;
+
+ ret = bpf_load_hdr_opt(skops, &tcp_opt, TCPOLEN_TIMESTAMP, 0);
+ if (ret != TCPOLEN_TIMESTAMP ||
+ !(skops->args[1] & BPF_SYNCOOKIE_TS))
+ goto err;
+
+ if (((skops->skb_tcp_flags & (TCPHDR_ECE | TCPHDR_CWR)) !=
+ (TCPHDR_ECE | TCPHDR_CWR)) ||
+ !(skops->args[1] & BPF_SYNCOOKIE_ECN))
+ goto err;
+
+ return CG_OK;
+
+err:
+ return CG_ERR;
+}
+
+static siphash_key_t test_key_siphash = {
+ { 0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL }
+};
+
+static __u32 cookie_hash(struct bpf_sock_ops *skops)
+{
+ return siphash_2u64((__u64)skops->remote_ip4 << 32 | skops->local_ip4,
+ (__u64)skops->remote_port << 32 | skops->local_port,
+ &test_key_siphash);
+}
+
+static const __u16 msstab[] = {
+ 536,
+ 1300,
+ 1440,
+ 1460,
+};
+
+#define COOKIE_BITS 8
+#define COOKIE_MASK (((__u32)1 << COOKIE_BITS) - 1)
+
+/* Hash is calculated for each client and split into
+ * ISN and TS.
+ *
+ * ISN:
+ *
+ * MSB LSB
+ * | 31 ... 8 | 7 6 | 5 | 4 | 3 2 1 0 |
+ * | Hash_1 | MSS | ECN | SACK | WScale |
+ *
+ * TS:
+ *
+ * MSB LSB
+ * | 31 ... 8 | 7 ... 0 |
+ * | Random | Hash_2 |
+ */
+static void gen_syncookie(struct bpf_sock_ops *skops)
+{
+ __u16 mss = skops->args[0];
+ __u32 tstamp = 0;
+ __u32 cookie;
+ int mssind;
+
+ for (mssind = ARRAY_SIZE(msstab) - 1; mssind; mssind--)
+ if (mss > msstab[mssind])
+ break;
+
+ cookie = cookie_hash(skops);
+
+ if (skops->args[1] & BPF_SYNCOOKIE_TS) {
+ tstamp = bpf_get_prandom_u32();
+ tstamp &= ~COOKIE_MASK;
+ tstamp |= cookie & COOKIE_MASK;
+ }
+
+ cookie &= ~COOKIE_MASK;
+ cookie |= mssind << 6;
+ cookie |= skops->args[1] & (BPF_SYNCOOKIE_ECN |
+ BPF_SYNCOOKIE_SACK |
+ BPF_SYNCOOKIE_WSCALE_MASK);
+
+ skops->replylong[0] = cookie;
+ skops->replylong[1] = tstamp;
+}
+
+static int check_syncookie(struct bpf_sock_ops *skops)
+{
+ __u32 cookie = cookie_hash(skops);
+ __u32 tstamp = skops->args[1];
+ __u8 mssind;
+
+ if (tstamp)
+ cookie -= tstamp & COOKIE_MASK;
+ else
+ cookie &= ~COOKIE_MASK;
+
+ cookie -= skops->args[0] & ~COOKIE_MASK;
+ if (cookie)
+ return CG_ERR;
+
+ mssind = (skops->args[0] & (3 << 6)) >> 6;
+ if (mssind > ARRAY_SIZE(msstab))
+ return CG_ERR;
+
+ /* msstab[mssind]; does not compile ... */
+ skops->replylong[0] = msstab[3];
+ skops->replylong[1] = skops->args[0] & (BPF_SYNCOOKIE_ECN |
+ BPF_SYNCOOKIE_SACK |
+ BPF_SYNCOOKIE_WSCALE_MASK);
+
+ return CG_OK;
+}
+
+SEC("sockops")
+int syncookie(struct bpf_sock_ops *skops)
+{
+ int ret = CG_OK;
+
+ switch (skops->op) {
+ case BPF_SOCK_OPS_TCP_LISTEN_CB:
+ bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_SYNCOOKIE_CB_FLAG);
+ break;
+ case BPF_SOCK_OPS_GEN_SYNCOOKIE_CB:
+ ret = assert_gen_syncookie_cb(skops);
+ if (ret)
+ gen_syncookie(skops);
+ break;
+ case BPF_SOCK_OPS_CHECK_SYNCOOKIE_CB:
+ ret = check_syncookie(skops);
+ break;
+ }
+
+ return ret;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_tcp_hdr_options.h b/tools/testing/selftests/bpf/test_tcp_hdr_options.h
index 56c9f8a3ad3d..3efca29a1394 100644
--- a/tools/testing/selftests/bpf/test_tcp_hdr_options.h
+++ b/tools/testing/selftests/bpf/test_tcp_hdr_options.h
@@ -52,8 +52,14 @@ struct linum_err {
#define TCPOPT_NOP 1
#define TCPOPT_MSS 2
#define TCPOPT_WINDOW 3
+#define TCPOPT_SACK_PERM 4
+#define TCPOPT_TIMESTAMP 8
#define TCPOPT_EXP 254
+#define TCPOLEN_WINDOW 3
+#define TCPOLEN_SACK_PERM 2
+#define TCPOLEN_TIMESTAMP 10
+
#define TCP_BPF_EXPOPT_BASE_LEN 4
#define MAX_TCP_HDR_LEN 60
#define MAX_TCP_OPTION_SPACE 40
@@ -81,7 +87,7 @@ struct tcp_opt {
__u8 kind;
__u8 len;
union {
- __u8 data[4];
+ __u8 data[8];
__u32 data32;
};
} __attribute__((packed));
--
2.30.2
next prev parent reply other threads:[~2023-10-13 22:10 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-13 22:04 [PATCH v1 bpf-next 00/11] bpf: tcp: Add SYN Cookie generation/validation SOCK_OPS hooks Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 01/11] tcp: Clean up reverse xmas tree in cookie_v[46]_check() Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 02/11] tcp: Cache sock_net(sk) " Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 03/11] tcp: Clean up goto labels " Kuniyuki Iwashima
2023-10-17 0:00 ` Kui-Feng Lee
2023-10-17 0:30 ` Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 04/11] tcp: Don't initialise tp->tsoffset in tcp_get_cookie_sock() Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 05/11] bpf: tcp: Add SYN Cookie generation SOCK_OPS hook Kuniyuki Iwashima
2023-10-18 0:54 ` Martin KaFai Lau
2023-10-18 17:00 ` Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 06/11] bpf: tcp: Add SYN Cookie validation " Kuniyuki Iwashima
2023-10-16 20:38 ` Stanislav Fomichev
2023-10-16 22:02 ` Kuniyuki Iwashima
2023-10-17 16:52 ` Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 07/11] bpf: Make bpf_sock_ops.replylong[1] writable Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 08/11] bpf: tcp: Make TS available for SYN Cookie storage Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 09/11] tcp: Split cookie_ecn_ok() Kuniyuki Iwashima
2023-10-13 22:04 ` [PATCH v1 bpf-next 10/11] bpf: tcp: Make WS, SACK, ECN configurable from BPF SYN Cookie Kuniyuki Iwashima
2023-10-18 1:08 ` Martin KaFai Lau
2023-10-18 17:02 ` Kuniyuki Iwashima
2023-10-13 22:04 ` Kuniyuki Iwashima [this message]
2023-10-17 5:50 ` [PATCH v1 bpf-next 11/11] selftest: bpf: Test BPF_SOCK_OPS_(GEN|CHECK)_SYNCOOKIE_CB Martin KaFai Lau
2023-10-17 16:29 ` Kuniyuki Iwashima
2023-10-16 13:05 ` [PATCH v1 bpf-next 00/11] bpf: tcp: Add SYN Cookie generation/validation SOCK_OPS hooks Daniel Borkmann
2023-10-16 16:11 ` Kuniyuki Iwashima
2023-10-16 14:19 ` Willem de Bruijn
2023-10-16 16:46 ` Kuniyuki Iwashima
2023-10-16 18:41 ` Willem de Bruijn
2023-10-17 5:53 ` Martin KaFai Lau
2023-10-17 16:48 ` Kuniyuki Iwashima
2023-10-18 6:19 ` Martin KaFai Lau
2023-10-18 8:02 ` Eric Dumazet
2023-10-18 17:20 ` Kuniyuki Iwashima
2023-10-18 21:47 ` Kui-Feng Lee
2023-10-18 22:31 ` Kuniyuki Iwashima
2023-10-19 7:25 ` Martin KaFai Lau
2023-10-19 18:01 ` Kuniyuki Iwashima
2023-10-20 19:59 ` Martin KaFai Lau
2023-10-20 23:10 ` Kuniyuki Iwashima
2023-10-21 6:48 ` Kuniyuki Iwashima
2023-10-23 21:35 ` Martin KaFai Lau
2023-10-24 0:37 ` Kui-Feng Lee
2023-10-24 1:22 ` Kuniyuki Iwashima
2023-10-24 17:55 ` Kui-Feng Lee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231013220433.70792-12-kuniyu@amazon.com \
--to=kuniyu@amazon.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=haoluo@google.com \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=kuba@kernel.org \
--cc=kuni1840@gmail.com \
--cc=martin.lau@linux.dev \
--cc=mykolal@fb.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@google.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).