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

sockmap_basic.c (11376B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (c) 2020 Cloudflare
      3#include <error.h>
      4#include <netinet/tcp.h>
      5
      6#include "test_progs.h"
      7#include "test_skmsg_load_helpers.skel.h"
      8#include "test_sockmap_update.skel.h"
      9#include "test_sockmap_invalid_update.skel.h"
     10#include "test_sockmap_skb_verdict_attach.skel.h"
     11#include "test_sockmap_progs_query.skel.h"
     12#include "bpf_iter_sockmap.skel.h"
     13
     14#define TCP_REPAIR		19	/* TCP sock is under repair right now */
     15
     16#define TCP_REPAIR_ON		1
     17#define TCP_REPAIR_OFF_NO_WP	-1	/* Turn off without window probes */
     18
     19static int connected_socket_v4(void)
     20{
     21	struct sockaddr_in addr = {
     22		.sin_family = AF_INET,
     23		.sin_port = htons(80),
     24		.sin_addr = { inet_addr("127.0.0.1") },
     25	};
     26	socklen_t len = sizeof(addr);
     27	int s, repair, err;
     28
     29	s = socket(AF_INET, SOCK_STREAM, 0);
     30	if (CHECK_FAIL(s == -1))
     31		goto error;
     32
     33	repair = TCP_REPAIR_ON;
     34	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
     35	if (CHECK_FAIL(err))
     36		goto error;
     37
     38	err = connect(s, (struct sockaddr *)&addr, len);
     39	if (CHECK_FAIL(err))
     40		goto error;
     41
     42	repair = TCP_REPAIR_OFF_NO_WP;
     43	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
     44	if (CHECK_FAIL(err))
     45		goto error;
     46
     47	return s;
     48error:
     49	perror(__func__);
     50	close(s);
     51	return -1;
     52}
     53
     54static void compare_cookies(struct bpf_map *src, struct bpf_map *dst)
     55{
     56	__u32 i, max_entries = bpf_map__max_entries(src);
     57	int err, duration = 0, src_fd, dst_fd;
     58
     59	src_fd = bpf_map__fd(src);
     60	dst_fd = bpf_map__fd(dst);
     61
     62	for (i = 0; i < max_entries; i++) {
     63		__u64 src_cookie, dst_cookie;
     64
     65		err = bpf_map_lookup_elem(src_fd, &i, &src_cookie);
     66		if (err && errno == ENOENT) {
     67			err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
     68			CHECK(!err, "map_lookup_elem(dst)", "element %u not deleted\n", i);
     69			CHECK(err && errno != ENOENT, "map_lookup_elem(dst)", "%s\n",
     70			      strerror(errno));
     71			continue;
     72		}
     73		if (CHECK(err, "lookup_elem(src)", "%s\n", strerror(errno)))
     74			continue;
     75
     76		err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
     77		if (CHECK(err, "lookup_elem(dst)", "%s\n", strerror(errno)))
     78			continue;
     79
     80		CHECK(dst_cookie != src_cookie, "cookie mismatch",
     81		      "%llu != %llu (pos %u)\n", dst_cookie, src_cookie, i);
     82	}
     83}
     84
     85/* Create a map, populate it with one socket, and free the map. */
     86static void test_sockmap_create_update_free(enum bpf_map_type map_type)
     87{
     88	const int zero = 0;
     89	int s, map, err;
     90
     91	s = connected_socket_v4();
     92	if (CHECK_FAIL(s < 0))
     93		return;
     94
     95	map = bpf_map_create(map_type, NULL, sizeof(int), sizeof(int), 1, NULL);
     96	if (CHECK_FAIL(map < 0)) {
     97		perror("bpf_cmap_create");
     98		goto out;
     99	}
    100
    101	err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST);
    102	if (CHECK_FAIL(err)) {
    103		perror("bpf_map_update");
    104		goto out;
    105	}
    106
    107out:
    108	close(map);
    109	close(s);
    110}
    111
    112static void test_skmsg_helpers(enum bpf_map_type map_type)
    113{
    114	struct test_skmsg_load_helpers *skel;
    115	int err, map, verdict;
    116
    117	skel = test_skmsg_load_helpers__open_and_load();
    118	if (CHECK_FAIL(!skel)) {
    119		perror("test_skmsg_load_helpers__open_and_load");
    120		return;
    121	}
    122
    123	verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
    124	map = bpf_map__fd(skel->maps.sock_map);
    125
    126	err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
    127	if (CHECK_FAIL(err)) {
    128		perror("bpf_prog_attach");
    129		goto out;
    130	}
    131
    132	err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT);
    133	if (CHECK_FAIL(err)) {
    134		perror("bpf_prog_detach2");
    135		goto out;
    136	}
    137out:
    138	test_skmsg_load_helpers__destroy(skel);
    139}
    140
    141static void test_sockmap_update(enum bpf_map_type map_type)
    142{
    143	int err, prog, src, duration = 0;
    144	struct test_sockmap_update *skel;
    145	struct bpf_map *dst_map;
    146	const __u32 zero = 0;
    147	char dummy[14] = {0};
    148	LIBBPF_OPTS(bpf_test_run_opts, topts,
    149		.data_in = dummy,
    150		.data_size_in = sizeof(dummy),
    151		.repeat = 1,
    152	);
    153	__s64 sk;
    154
    155	sk = connected_socket_v4();
    156	if (CHECK(sk == -1, "connected_socket_v4", "cannot connect\n"))
    157		return;
    158
    159	skel = test_sockmap_update__open_and_load();
    160	if (CHECK(!skel, "open_and_load", "cannot load skeleton\n"))
    161		goto close_sk;
    162
    163	prog = bpf_program__fd(skel->progs.copy_sock_map);
    164	src = bpf_map__fd(skel->maps.src);
    165	if (map_type == BPF_MAP_TYPE_SOCKMAP)
    166		dst_map = skel->maps.dst_sock_map;
    167	else
    168		dst_map = skel->maps.dst_sock_hash;
    169
    170	err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
    171	if (CHECK(err, "update_elem(src)", "errno=%u\n", errno))
    172		goto out;
    173
    174	err = bpf_prog_test_run_opts(prog, &topts);
    175	if (!ASSERT_OK(err, "test_run"))
    176		goto out;
    177	if (!ASSERT_NEQ(topts.retval, 0, "test_run retval"))
    178		goto out;
    179
    180	compare_cookies(skel->maps.src, dst_map);
    181
    182out:
    183	test_sockmap_update__destroy(skel);
    184close_sk:
    185	close(sk);
    186}
    187
    188static void test_sockmap_invalid_update(void)
    189{
    190	struct test_sockmap_invalid_update *skel;
    191	int duration = 0;
    192
    193	skel = test_sockmap_invalid_update__open_and_load();
    194	if (CHECK(skel, "open_and_load", "verifier accepted map_update\n"))
    195		test_sockmap_invalid_update__destroy(skel);
    196}
    197
    198static void test_sockmap_copy(enum bpf_map_type map_type)
    199{
    200	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
    201	int err, len, src_fd, iter_fd, duration = 0;
    202	union bpf_iter_link_info linfo = {};
    203	__u32 i, num_sockets, num_elems;
    204	struct bpf_iter_sockmap *skel;
    205	__s64 *sock_fd = NULL;
    206	struct bpf_link *link;
    207	struct bpf_map *src;
    208	char buf[64];
    209
    210	skel = bpf_iter_sockmap__open_and_load();
    211	if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", "skeleton open_and_load failed\n"))
    212		return;
    213
    214	if (map_type == BPF_MAP_TYPE_SOCKMAP) {
    215		src = skel->maps.sockmap;
    216		num_elems = bpf_map__max_entries(src);
    217		num_sockets = num_elems - 1;
    218	} else {
    219		src = skel->maps.sockhash;
    220		num_elems = bpf_map__max_entries(src) - 1;
    221		num_sockets = num_elems;
    222	}
    223
    224	sock_fd = calloc(num_sockets, sizeof(*sock_fd));
    225	if (CHECK(!sock_fd, "calloc(sock_fd)", "failed to allocate\n"))
    226		goto out;
    227
    228	for (i = 0; i < num_sockets; i++)
    229		sock_fd[i] = -1;
    230
    231	src_fd = bpf_map__fd(src);
    232
    233	for (i = 0; i < num_sockets; i++) {
    234		sock_fd[i] = connected_socket_v4();
    235		if (CHECK(sock_fd[i] == -1, "connected_socket_v4", "cannot connect\n"))
    236			goto out;
    237
    238		err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST);
    239		if (CHECK(err, "map_update", "failed: %s\n", strerror(errno)))
    240			goto out;
    241	}
    242
    243	linfo.map.map_fd = src_fd;
    244	opts.link_info = &linfo;
    245	opts.link_info_len = sizeof(linfo);
    246	link = bpf_program__attach_iter(skel->progs.copy, &opts);
    247	if (!ASSERT_OK_PTR(link, "attach_iter"))
    248		goto out;
    249
    250	iter_fd = bpf_iter_create(bpf_link__fd(link));
    251	if (CHECK(iter_fd < 0, "create_iter", "create_iter failed\n"))
    252		goto free_link;
    253
    254	/* do some tests */
    255	while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
    256		;
    257	if (CHECK(len < 0, "read", "failed: %s\n", strerror(errno)))
    258		goto close_iter;
    259
    260	/* test results */
    261	if (CHECK(skel->bss->elems != num_elems, "elems", "got %u expected %u\n",
    262		  skel->bss->elems, num_elems))
    263		goto close_iter;
    264
    265	if (CHECK(skel->bss->socks != num_sockets, "socks", "got %u expected %u\n",
    266		  skel->bss->socks, num_sockets))
    267		goto close_iter;
    268
    269	compare_cookies(src, skel->maps.dst);
    270
    271close_iter:
    272	close(iter_fd);
    273free_link:
    274	bpf_link__destroy(link);
    275out:
    276	for (i = 0; sock_fd && i < num_sockets; i++)
    277		if (sock_fd[i] >= 0)
    278			close(sock_fd[i]);
    279	if (sock_fd)
    280		free(sock_fd);
    281	bpf_iter_sockmap__destroy(skel);
    282}
    283
    284static void test_sockmap_skb_verdict_attach(enum bpf_attach_type first,
    285					    enum bpf_attach_type second)
    286{
    287	struct test_sockmap_skb_verdict_attach *skel;
    288	int err, map, verdict;
    289
    290	skel = test_sockmap_skb_verdict_attach__open_and_load();
    291	if (CHECK_FAIL(!skel)) {
    292		perror("test_sockmap_skb_verdict_attach__open_and_load");
    293		return;
    294	}
    295
    296	verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
    297	map = bpf_map__fd(skel->maps.sock_map);
    298
    299	err = bpf_prog_attach(verdict, map, first, 0);
    300	if (CHECK_FAIL(err)) {
    301		perror("bpf_prog_attach");
    302		goto out;
    303	}
    304
    305	err = bpf_prog_attach(verdict, map, second, 0);
    306	ASSERT_EQ(err, -EBUSY, "prog_attach_fail");
    307
    308	err = bpf_prog_detach2(verdict, map, first);
    309	if (CHECK_FAIL(err)) {
    310		perror("bpf_prog_detach2");
    311		goto out;
    312	}
    313out:
    314	test_sockmap_skb_verdict_attach__destroy(skel);
    315}
    316
    317static __u32 query_prog_id(int prog_fd)
    318{
    319	struct bpf_prog_info info = {};
    320	__u32 info_len = sizeof(info);
    321	int err;
    322
    323	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
    324	if (!ASSERT_OK(err, "bpf_obj_get_info_by_fd") ||
    325	    !ASSERT_EQ(info_len, sizeof(info), "bpf_obj_get_info_by_fd"))
    326		return 0;
    327
    328	return info.id;
    329}
    330
    331static void test_sockmap_progs_query(enum bpf_attach_type attach_type)
    332{
    333	struct test_sockmap_progs_query *skel;
    334	int err, map_fd, verdict_fd;
    335	__u32 attach_flags = 0;
    336	__u32 prog_ids[3] = {};
    337	__u32 prog_cnt = 3;
    338
    339	skel = test_sockmap_progs_query__open_and_load();
    340	if (!ASSERT_OK_PTR(skel, "test_sockmap_progs_query__open_and_load"))
    341		return;
    342
    343	map_fd = bpf_map__fd(skel->maps.sock_map);
    344
    345	if (attach_type == BPF_SK_MSG_VERDICT)
    346		verdict_fd = bpf_program__fd(skel->progs.prog_skmsg_verdict);
    347	else
    348		verdict_fd = bpf_program__fd(skel->progs.prog_skb_verdict);
    349
    350	err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
    351			     &attach_flags, prog_ids, &prog_cnt);
    352	ASSERT_OK(err, "bpf_prog_query failed");
    353	ASSERT_EQ(attach_flags,  0, "wrong attach_flags on query");
    354	ASSERT_EQ(prog_cnt, 0, "wrong program count on query");
    355
    356	err = bpf_prog_attach(verdict_fd, map_fd, attach_type, 0);
    357	if (!ASSERT_OK(err, "bpf_prog_attach failed"))
    358		goto out;
    359
    360	prog_cnt = 1;
    361	err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
    362			     &attach_flags, prog_ids, &prog_cnt);
    363	ASSERT_OK(err, "bpf_prog_query failed");
    364	ASSERT_EQ(attach_flags, 0, "wrong attach_flags on query");
    365	ASSERT_EQ(prog_cnt, 1, "wrong program count on query");
    366	ASSERT_EQ(prog_ids[0], query_prog_id(verdict_fd),
    367		  "wrong prog_ids on query");
    368
    369	bpf_prog_detach2(verdict_fd, map_fd, attach_type);
    370out:
    371	test_sockmap_progs_query__destroy(skel);
    372}
    373
    374void test_sockmap_basic(void)
    375{
    376	if (test__start_subtest("sockmap create_update_free"))
    377		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP);
    378	if (test__start_subtest("sockhash create_update_free"))
    379		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH);
    380	if (test__start_subtest("sockmap sk_msg load helpers"))
    381		test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP);
    382	if (test__start_subtest("sockhash sk_msg load helpers"))
    383		test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH);
    384	if (test__start_subtest("sockmap update"))
    385		test_sockmap_update(BPF_MAP_TYPE_SOCKMAP);
    386	if (test__start_subtest("sockhash update"))
    387		test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
    388	if (test__start_subtest("sockmap update in unsafe context"))
    389		test_sockmap_invalid_update();
    390	if (test__start_subtest("sockmap copy"))
    391		test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
    392	if (test__start_subtest("sockhash copy"))
    393		test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
    394	if (test__start_subtest("sockmap skb_verdict attach")) {
    395		test_sockmap_skb_verdict_attach(BPF_SK_SKB_VERDICT,
    396						BPF_SK_SKB_STREAM_VERDICT);
    397		test_sockmap_skb_verdict_attach(BPF_SK_SKB_STREAM_VERDICT,
    398						BPF_SK_SKB_VERDICT);
    399	}
    400	if (test__start_subtest("sockmap msg_verdict progs query"))
    401		test_sockmap_progs_query(BPF_SK_MSG_VERDICT);
    402	if (test__start_subtest("sockmap stream_parser progs query"))
    403		test_sockmap_progs_query(BPF_SK_SKB_STREAM_PARSER);
    404	if (test__start_subtest("sockmap stream_verdict progs query"))
    405		test_sockmap_progs_query(BPF_SK_SKB_STREAM_VERDICT);
    406	if (test__start_subtest("sockmap skb_verdict progs query"))
    407		test_sockmap_progs_query(BPF_SK_SKB_VERDICT);
    408}