cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tcp_hdr_options.c (15210B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2020 Facebook */
      3
      4#define _GNU_SOURCE
      5#include <sched.h>
      6#include <stdio.h>
      7#include <stdlib.h>
      8#include <sys/socket.h>
      9#include <linux/compiler.h>
     10
     11#include "test_progs.h"
     12#include "cgroup_helpers.h"
     13#include "network_helpers.h"
     14#include "test_tcp_hdr_options.h"
     15#include "test_tcp_hdr_options.skel.h"
     16#include "test_misc_tcp_hdr_options.skel.h"
     17
     18#define LO_ADDR6 "::1"
     19#define CG_NAME "/tcpbpf-hdr-opt-test"
     20
     21static struct bpf_test_option exp_passive_estab_in;
     22static struct bpf_test_option exp_active_estab_in;
     23static struct bpf_test_option exp_passive_fin_in;
     24static struct bpf_test_option exp_active_fin_in;
     25static struct hdr_stg exp_passive_hdr_stg;
     26static struct hdr_stg exp_active_hdr_stg = { .active = true, };
     27
     28static struct test_misc_tcp_hdr_options *misc_skel;
     29static struct test_tcp_hdr_options *skel;
     30static int lport_linum_map_fd;
     31static int hdr_stg_map_fd;
     32static __u32 duration;
     33static int cg_fd;
     34
     35struct sk_fds {
     36	int srv_fd;
     37	int passive_fd;
     38	int active_fd;
     39	int passive_lport;
     40	int active_lport;
     41};
     42
     43static int create_netns(void)
     44{
     45	if (CHECK(unshare(CLONE_NEWNET), "create netns",
     46		  "unshare(CLONE_NEWNET): %s (%d)",
     47		  strerror(errno), errno))
     48		return -1;
     49
     50	if (CHECK(system("ip link set dev lo up"), "run ip cmd",
     51		  "failed to bring lo link up\n"))
     52		return -1;
     53
     54	return 0;
     55}
     56
     57static int write_sysctl(const char *sysctl, const char *value)
     58{
     59	int fd, err, len;
     60
     61	fd = open(sysctl, O_WRONLY);
     62	if (CHECK(fd == -1, "open sysctl", "open(%s): %s (%d)\n",
     63		  sysctl, strerror(errno), errno))
     64		return -1;
     65
     66	len = strlen(value);
     67	err = write(fd, value, len);
     68	close(fd);
     69	if (CHECK(err != len, "write sysctl",
     70		  "write(%s, %s): err:%d %s (%d)\n",
     71		  sysctl, value, err, strerror(errno), errno))
     72		return -1;
     73
     74	return 0;
     75}
     76
     77static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)
     78{
     79	fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",
     80		prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,
     81		hdr_stg->syncookie, hdr_stg->fastopen);
     82}
     83
     84static void print_option(const struct bpf_test_option *opt, const char *prefix)
     85{
     86	fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",
     87		prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);
     88}
     89
     90static void sk_fds_close(struct sk_fds *sk_fds)
     91{
     92	close(sk_fds->srv_fd);
     93	close(sk_fds->passive_fd);
     94	close(sk_fds->active_fd);
     95}
     96
     97static int sk_fds_shutdown(struct sk_fds *sk_fds)
     98{
     99	int ret, abyte;
    100
    101	shutdown(sk_fds->active_fd, SHUT_WR);
    102	ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));
    103	if (CHECK(ret != 0, "read-after-shutdown(passive_fd):",
    104		  "ret:%d %s (%d)\n",
    105		  ret, strerror(errno), errno))
    106		return -1;
    107
    108	shutdown(sk_fds->passive_fd, SHUT_WR);
    109	ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));
    110	if (CHECK(ret != 0, "read-after-shutdown(active_fd):",
    111		  "ret:%d %s (%d)\n",
    112		  ret, strerror(errno), errno))
    113		return -1;
    114
    115	return 0;
    116}
    117
    118static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)
    119{
    120	const char fast[] = "FAST!!!";
    121	struct sockaddr_in6 addr6;
    122	socklen_t len;
    123
    124	sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
    125	if (CHECK(sk_fds->srv_fd == -1, "start_server", "%s (%d)\n",
    126		  strerror(errno), errno))
    127		goto error;
    128
    129	if (fast_open)
    130		sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,
    131						     sizeof(fast), 0);
    132	else
    133		sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);
    134
    135	if (CHECK_FAIL(sk_fds->active_fd == -1)) {
    136		close(sk_fds->srv_fd);
    137		goto error;
    138	}
    139
    140	len = sizeof(addr6);
    141	if (CHECK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,
    142			      &len), "getsockname(srv_fd)", "%s (%d)\n",
    143		  strerror(errno), errno))
    144		goto error_close;
    145	sk_fds->passive_lport = ntohs(addr6.sin6_port);
    146
    147	len = sizeof(addr6);
    148	if (CHECK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,
    149			      &len), "getsockname(active_fd)", "%s (%d)\n",
    150		  strerror(errno), errno))
    151		goto error_close;
    152	sk_fds->active_lport = ntohs(addr6.sin6_port);
    153
    154	sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);
    155	if (CHECK(sk_fds->passive_fd == -1, "accept(srv_fd)", "%s (%d)\n",
    156		  strerror(errno), errno))
    157		goto error_close;
    158
    159	if (fast_open) {
    160		char bytes_in[sizeof(fast)];
    161		int ret;
    162
    163		ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));
    164		if (CHECK(ret != sizeof(fast), "read fastopen syn data",
    165			  "expected=%lu actual=%d\n", sizeof(fast), ret)) {
    166			close(sk_fds->passive_fd);
    167			goto error_close;
    168		}
    169	}
    170
    171	return 0;
    172
    173error_close:
    174	close(sk_fds->active_fd);
    175	close(sk_fds->srv_fd);
    176
    177error:
    178	memset(sk_fds, -1, sizeof(*sk_fds));
    179	return -1;
    180}
    181
    182static int check_hdr_opt(const struct bpf_test_option *exp,
    183			 const struct bpf_test_option *act,
    184			 const char *hdr_desc)
    185{
    186	if (CHECK(memcmp(exp, act, sizeof(*exp)),
    187		  "expected-vs-actual", "unexpected %s\n", hdr_desc)) {
    188		print_option(exp, "expected: ");
    189		print_option(act, "  actual: ");
    190		return -1;
    191	}
    192
    193	return 0;
    194}
    195
    196static int check_hdr_stg(const struct hdr_stg *exp, int fd,
    197			 const char *stg_desc)
    198{
    199	struct hdr_stg act;
    200
    201	if (CHECK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),
    202		  "map_lookup(hdr_stg_map_fd)", "%s %s (%d)\n",
    203		  stg_desc, strerror(errno), errno))
    204		return -1;
    205
    206	if (CHECK(memcmp(exp, &act, sizeof(*exp)),
    207		  "expected-vs-actual", "unexpected %s\n", stg_desc)) {
    208		print_hdr_stg(exp, "expected: ");
    209		print_hdr_stg(&act, "  actual: ");
    210		return -1;
    211	}
    212
    213	return 0;
    214}
    215
    216static int check_error_linum(const struct sk_fds *sk_fds)
    217{
    218	unsigned int nr_errors = 0;
    219	struct linum_err linum_err;
    220	int lport;
    221
    222	lport = sk_fds->passive_lport;
    223	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
    224		fprintf(stderr,
    225			"bpf prog error out at lport:passive(%d), linum:%u err:%d\n",
    226			lport, linum_err.linum, linum_err.err);
    227		nr_errors++;
    228	}
    229
    230	lport = sk_fds->active_lport;
    231	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
    232		fprintf(stderr,
    233			"bpf prog error out at lport:active(%d), linum:%u err:%d\n",
    234			lport, linum_err.linum, linum_err.err);
    235		nr_errors++;
    236	}
    237
    238	return nr_errors;
    239}
    240
    241static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
    242{
    243	const __u32 expected_inherit_cb_flags =
    244		BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
    245		BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
    246		BPF_SOCK_OPS_STATE_CB_FLAG;
    247
    248	if (sk_fds_shutdown(sk_fds))
    249		goto check_linum;
    250
    251	if (CHECK(expected_inherit_cb_flags != skel->bss->inherit_cb_flags,
    252		  "Unexpected inherit_cb_flags", "0x%x != 0x%x\n",
    253		  skel->bss->inherit_cb_flags, expected_inherit_cb_flags))
    254		goto check_linum;
    255
    256	if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
    257			  "passive_hdr_stg"))
    258		goto check_linum;
    259
    260	if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,
    261			  "active_hdr_stg"))
    262		goto check_linum;
    263
    264	if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,
    265			  "passive_estab_in"))
    266		goto check_linum;
    267
    268	if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,
    269			  "active_estab_in"))
    270		goto check_linum;
    271
    272	if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,
    273			  "passive_fin_in"))
    274		goto check_linum;
    275
    276	check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,
    277		      "active_fin_in");
    278
    279check_linum:
    280	CHECK_FAIL(check_error_linum(sk_fds));
    281	sk_fds_close(sk_fds);
    282}
    283
    284static void prepare_out(void)
    285{
    286	skel->bss->active_syn_out = exp_passive_estab_in;
    287	skel->bss->passive_synack_out = exp_active_estab_in;
    288
    289	skel->bss->active_fin_out = exp_passive_fin_in;
    290	skel->bss->passive_fin_out = exp_active_fin_in;
    291}
    292
    293static void reset_test(void)
    294{
    295	size_t optsize = sizeof(struct bpf_test_option);
    296	int lport, err;
    297
    298	memset(&skel->bss->passive_synack_out, 0, optsize);
    299	memset(&skel->bss->passive_fin_out, 0, optsize);
    300
    301	memset(&skel->bss->passive_estab_in, 0, optsize);
    302	memset(&skel->bss->passive_fin_in, 0, optsize);
    303
    304	memset(&skel->bss->active_syn_out, 0, optsize);
    305	memset(&skel->bss->active_fin_out, 0, optsize);
    306
    307	memset(&skel->bss->active_estab_in, 0, optsize);
    308	memset(&skel->bss->active_fin_in, 0, optsize);
    309
    310	skel->bss->inherit_cb_flags = 0;
    311
    312	skel->data->test_kind = TCPOPT_EXP;
    313	skel->data->test_magic = 0xeB9F;
    314
    315	memset(&exp_passive_estab_in, 0, optsize);
    316	memset(&exp_active_estab_in, 0, optsize);
    317	memset(&exp_passive_fin_in, 0, optsize);
    318	memset(&exp_active_fin_in, 0, optsize);
    319
    320	memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));
    321	memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));
    322	exp_active_hdr_stg.active = true;
    323
    324	err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);
    325	while (!err) {
    326		bpf_map_delete_elem(lport_linum_map_fd, &lport);
    327		err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);
    328	}
    329}
    330
    331static void fastopen_estab(void)
    332{
    333	struct bpf_link *link;
    334	struct sk_fds sk_fds;
    335
    336	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
    337	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
    338
    339	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
    340	exp_passive_estab_in.rand = 0xfa;
    341	exp_passive_estab_in.max_delack_ms = 11;
    342
    343	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
    344	exp_active_estab_in.rand = 0xce;
    345	exp_active_estab_in.max_delack_ms = 22;
    346
    347	exp_passive_hdr_stg.fastopen = true;
    348
    349	prepare_out();
    350
    351	/* Allow fastopen without fastopen cookie */
    352	if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))
    353		return;
    354
    355	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
    356	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
    357		return;
    358
    359	if (sk_fds_connect(&sk_fds, true)) {
    360		bpf_link__destroy(link);
    361		return;
    362	}
    363
    364	check_hdr_and_close_fds(&sk_fds);
    365	bpf_link__destroy(link);
    366}
    367
    368static void syncookie_estab(void)
    369{
    370	struct bpf_link *link;
    371	struct sk_fds sk_fds;
    372
    373	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
    374	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
    375
    376	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
    377	exp_passive_estab_in.rand = 0xfa;
    378	exp_passive_estab_in.max_delack_ms = 11;
    379
    380	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |
    381					OPTION_F_RESEND;
    382	exp_active_estab_in.rand = 0xce;
    383	exp_active_estab_in.max_delack_ms = 22;
    384
    385	exp_passive_hdr_stg.syncookie = true;
    386	exp_active_hdr_stg.resend_syn = true,
    387
    388	prepare_out();
    389
    390	/* Clear the RESEND to ensure the bpf prog can learn
    391	 * want_cookie and set the RESEND by itself.
    392	 */
    393	skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;
    394
    395	/* Enforce syncookie mode */
    396	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
    397		return;
    398
    399	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
    400	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
    401		return;
    402
    403	if (sk_fds_connect(&sk_fds, false)) {
    404		bpf_link__destroy(link);
    405		return;
    406	}
    407
    408	check_hdr_and_close_fds(&sk_fds);
    409	bpf_link__destroy(link);
    410}
    411
    412static void fin(void)
    413{
    414	struct bpf_link *link;
    415	struct sk_fds sk_fds;
    416
    417	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
    418	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
    419
    420	exp_passive_fin_in.flags = OPTION_F_RAND;
    421	exp_passive_fin_in.rand = 0xfa;
    422
    423	exp_active_fin_in.flags = OPTION_F_RAND;
    424	exp_active_fin_in.rand = 0xce;
    425
    426	prepare_out();
    427
    428	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
    429		return;
    430
    431	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
    432	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
    433		return;
    434
    435	if (sk_fds_connect(&sk_fds, false)) {
    436		bpf_link__destroy(link);
    437		return;
    438	}
    439
    440	check_hdr_and_close_fds(&sk_fds);
    441	bpf_link__destroy(link);
    442}
    443
    444static void __simple_estab(bool exprm)
    445{
    446	struct bpf_link *link;
    447	struct sk_fds sk_fds;
    448
    449	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
    450	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
    451
    452	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
    453	exp_passive_estab_in.rand = 0xfa;
    454	exp_passive_estab_in.max_delack_ms = 11;
    455
    456	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
    457	exp_active_estab_in.rand = 0xce;
    458	exp_active_estab_in.max_delack_ms = 22;
    459
    460	prepare_out();
    461
    462	if (!exprm) {
    463		skel->data->test_kind = 0xB9;
    464		skel->data->test_magic = 0;
    465	}
    466
    467	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
    468		return;
    469
    470	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
    471	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
    472		return;
    473
    474	if (sk_fds_connect(&sk_fds, false)) {
    475		bpf_link__destroy(link);
    476		return;
    477	}
    478
    479	check_hdr_and_close_fds(&sk_fds);
    480	bpf_link__destroy(link);
    481}
    482
    483static void no_exprm_estab(void)
    484{
    485	__simple_estab(false);
    486}
    487
    488static void simple_estab(void)
    489{
    490	__simple_estab(true);
    491}
    492
    493static void misc(void)
    494{
    495	const char send_msg[] = "MISC!!!";
    496	char recv_msg[sizeof(send_msg)];
    497	const unsigned int nr_data = 2;
    498	struct bpf_link *link;
    499	struct sk_fds sk_fds;
    500	int i, ret;
    501
    502	lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);
    503
    504	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
    505		return;
    506
    507	link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);
    508	if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)"))
    509		return;
    510
    511	if (sk_fds_connect(&sk_fds, false)) {
    512		bpf_link__destroy(link);
    513		return;
    514	}
    515
    516	for (i = 0; i < nr_data; i++) {
    517		/* MSG_EOR to ensure skb will not be combined */
    518		ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),
    519			   MSG_EOR);
    520		if (CHECK(ret != sizeof(send_msg), "send(msg)", "ret:%d\n",
    521			  ret))
    522			goto check_linum;
    523
    524		ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));
    525		if (CHECK(ret != sizeof(send_msg), "read(msg)", "ret:%d\n",
    526			  ret))
    527			goto check_linum;
    528	}
    529
    530	if (sk_fds_shutdown(&sk_fds))
    531		goto check_linum;
    532
    533	CHECK(misc_skel->bss->nr_syn != 1, "unexpected nr_syn",
    534	      "expected (1) != actual (%u)\n",
    535		misc_skel->bss->nr_syn);
    536
    537	CHECK(misc_skel->bss->nr_data != nr_data, "unexpected nr_data",
    538	      "expected (%u) != actual (%u)\n",
    539	      nr_data, misc_skel->bss->nr_data);
    540
    541	/* The last ACK may have been delayed, so it is either 1 or 2. */
    542	CHECK(misc_skel->bss->nr_pure_ack != 1 &&
    543	      misc_skel->bss->nr_pure_ack != 2,
    544	      "unexpected nr_pure_ack",
    545	      "expected (1 or 2) != actual (%u)\n",
    546		misc_skel->bss->nr_pure_ack);
    547
    548	CHECK(misc_skel->bss->nr_fin != 1, "unexpected nr_fin",
    549	      "expected (1) != actual (%u)\n",
    550	      misc_skel->bss->nr_fin);
    551
    552check_linum:
    553	CHECK_FAIL(check_error_linum(&sk_fds));
    554	sk_fds_close(&sk_fds);
    555	bpf_link__destroy(link);
    556}
    557
    558struct test {
    559	const char *desc;
    560	void (*run)(void);
    561};
    562
    563#define DEF_TEST(name) { #name, name }
    564static struct test tests[] = {
    565	DEF_TEST(simple_estab),
    566	DEF_TEST(no_exprm_estab),
    567	DEF_TEST(syncookie_estab),
    568	DEF_TEST(fastopen_estab),
    569	DEF_TEST(fin),
    570	DEF_TEST(misc),
    571};
    572
    573void test_tcp_hdr_options(void)
    574{
    575	int i;
    576
    577	skel = test_tcp_hdr_options__open_and_load();
    578	if (CHECK(!skel, "open and load skel", "failed"))
    579		return;
    580
    581	misc_skel = test_misc_tcp_hdr_options__open_and_load();
    582	if (CHECK(!misc_skel, "open and load misc test skel", "failed"))
    583		goto skel_destroy;
    584
    585	cg_fd = test__join_cgroup(CG_NAME);
    586	if (CHECK_FAIL(cg_fd < 0))
    587		goto skel_destroy;
    588
    589	for (i = 0; i < ARRAY_SIZE(tests); i++) {
    590		if (!test__start_subtest(tests[i].desc))
    591			continue;
    592
    593		if (create_netns())
    594			break;
    595
    596		tests[i].run();
    597
    598		reset_test();
    599	}
    600
    601	close(cg_fd);
    602skel_destroy:
    603	test_misc_tcp_hdr_options__destroy(misc_skel);
    604	test_tcp_hdr_options__destroy(skel);
    605}