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

cg_storage_multi.c (13592B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3/*
      4 * Copyright 2020 Google LLC.
      5 */
      6
      7#include <test_progs.h>
      8#include <cgroup_helpers.h>
      9#include <network_helpers.h>
     10
     11#include "progs/cg_storage_multi.h"
     12
     13#include "cg_storage_multi_egress_only.skel.h"
     14#include "cg_storage_multi_isolated.skel.h"
     15#include "cg_storage_multi_shared.skel.h"
     16
     17#define PARENT_CGROUP "/cgroup_storage"
     18#define CHILD_CGROUP "/cgroup_storage/child"
     19
     20static int duration;
     21
     22static bool assert_storage(struct bpf_map *map, const void *key,
     23			   struct cgroup_value *expected)
     24{
     25	struct cgroup_value value;
     26	int map_fd;
     27
     28	map_fd = bpf_map__fd(map);
     29
     30	if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
     31		  "map-lookup", "errno %d", errno))
     32		return true;
     33	if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
     34		  "assert-storage", "storages differ"))
     35		return true;
     36
     37	return false;
     38}
     39
     40static bool assert_storage_noexist(struct bpf_map *map, const void *key)
     41{
     42	struct cgroup_value value;
     43	int map_fd;
     44
     45	map_fd = bpf_map__fd(map);
     46
     47	if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
     48		  "map-lookup", "succeeded, expected ENOENT"))
     49		return true;
     50	if (CHECK(errno != ENOENT,
     51		  "map-lookup", "errno %d, expected ENOENT", errno))
     52		return true;
     53
     54	return false;
     55}
     56
     57static bool connect_send(const char *cgroup_path)
     58{
     59	bool res = true;
     60	int server_fd = -1, client_fd = -1;
     61
     62	if (join_cgroup(cgroup_path))
     63		goto out_clean;
     64
     65	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
     66	if (server_fd < 0)
     67		goto out_clean;
     68
     69	client_fd = connect_to_fd(server_fd, 0);
     70	if (client_fd < 0)
     71		goto out_clean;
     72
     73	if (send(client_fd, "message", strlen("message"), 0) < 0)
     74		goto out_clean;
     75
     76	res = false;
     77
     78out_clean:
     79	close(client_fd);
     80	close(server_fd);
     81	return res;
     82}
     83
     84static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
     85{
     86	struct cg_storage_multi_egress_only *obj;
     87	struct cgroup_value expected_cgroup_value;
     88	struct bpf_cgroup_storage_key key;
     89	struct bpf_link *parent_link = NULL, *child_link = NULL;
     90	bool err;
     91
     92	key.attach_type = BPF_CGROUP_INET_EGRESS;
     93
     94	obj = cg_storage_multi_egress_only__open_and_load();
     95	if (CHECK(!obj, "skel-load", "errno %d", errno))
     96		return;
     97
     98	/* Attach to parent cgroup, trigger packet from child.
     99	 * Assert that there is only one run and in that run the storage is
    100	 * parent cgroup's storage.
    101	 * Also assert that child cgroup's storage does not exist
    102	 */
    103	parent_link = bpf_program__attach_cgroup(obj->progs.egress,
    104						 parent_cgroup_fd);
    105	if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
    106		goto close_bpf_object;
    107	err = connect_send(CHILD_CGROUP);
    108	if (CHECK(err, "first-connect-send", "errno %d", errno))
    109		goto close_bpf_object;
    110	if (CHECK(obj->bss->invocations != 1,
    111		  "first-invoke", "invocations=%d", obj->bss->invocations))
    112		goto close_bpf_object;
    113	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
    114	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
    115	if (assert_storage(obj->maps.cgroup_storage,
    116			   &key, &expected_cgroup_value))
    117		goto close_bpf_object;
    118	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
    119	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
    120		goto close_bpf_object;
    121
    122	/* Attach to parent and child cgroup, trigger packet from child.
    123	 * Assert that there are two additional runs, one that run with parent
    124	 * cgroup's storage and one with child cgroup's storage.
    125	 */
    126	child_link = bpf_program__attach_cgroup(obj->progs.egress,
    127						child_cgroup_fd);
    128	if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
    129		goto close_bpf_object;
    130	err = connect_send(CHILD_CGROUP);
    131	if (CHECK(err, "second-connect-send", "errno %d", errno))
    132		goto close_bpf_object;
    133	if (CHECK(obj->bss->invocations != 3,
    134		  "second-invoke", "invocations=%d", obj->bss->invocations))
    135		goto close_bpf_object;
    136	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
    137	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
    138	if (assert_storage(obj->maps.cgroup_storage,
    139			   &key, &expected_cgroup_value))
    140		goto close_bpf_object;
    141	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
    142	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
    143	if (assert_storage(obj->maps.cgroup_storage,
    144			   &key, &expected_cgroup_value))
    145		goto close_bpf_object;
    146
    147close_bpf_object:
    148	bpf_link__destroy(parent_link);
    149	bpf_link__destroy(child_link);
    150
    151	cg_storage_multi_egress_only__destroy(obj);
    152}
    153
    154static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
    155{
    156	struct cg_storage_multi_isolated *obj;
    157	struct cgroup_value expected_cgroup_value;
    158	struct bpf_cgroup_storage_key key;
    159	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
    160	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
    161	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
    162	bool err;
    163
    164	obj = cg_storage_multi_isolated__open_and_load();
    165	if (CHECK(!obj, "skel-load", "errno %d", errno))
    166		return;
    167
    168	/* Attach to parent cgroup, trigger packet from child.
    169	 * Assert that there is three runs, two with parent cgroup egress and
    170	 * one with parent cgroup ingress, stored in separate parent storages.
    171	 * Also assert that child cgroup's storages does not exist
    172	 */
    173	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
    174							 parent_cgroup_fd);
    175	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
    176		goto close_bpf_object;
    177	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
    178							 parent_cgroup_fd);
    179	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
    180		goto close_bpf_object;
    181	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
    182							 parent_cgroup_fd);
    183	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
    184		goto close_bpf_object;
    185	err = connect_send(CHILD_CGROUP);
    186	if (CHECK(err, "first-connect-send", "errno %d", errno))
    187		goto close_bpf_object;
    188	if (CHECK(obj->bss->invocations != 3,
    189		  "first-invoke", "invocations=%d", obj->bss->invocations))
    190		goto close_bpf_object;
    191	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
    192	key.attach_type = BPF_CGROUP_INET_EGRESS;
    193	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
    194	if (assert_storage(obj->maps.cgroup_storage,
    195			   &key, &expected_cgroup_value))
    196		goto close_bpf_object;
    197	key.attach_type = BPF_CGROUP_INET_INGRESS;
    198	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
    199	if (assert_storage(obj->maps.cgroup_storage,
    200			   &key, &expected_cgroup_value))
    201		goto close_bpf_object;
    202	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
    203	key.attach_type = BPF_CGROUP_INET_EGRESS;
    204	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
    205		goto close_bpf_object;
    206	key.attach_type = BPF_CGROUP_INET_INGRESS;
    207	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
    208		goto close_bpf_object;
    209
    210	/* Attach to parent and child cgroup, trigger packet from child.
    211	 * Assert that there is six additional runs, parent cgroup egresses and
    212	 * ingress, child cgroup egresses and ingress.
    213	 * Assert that egree and ingress storages are separate.
    214	 */
    215	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
    216							child_cgroup_fd);
    217	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
    218		goto close_bpf_object;
    219	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
    220							child_cgroup_fd);
    221	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
    222		goto close_bpf_object;
    223	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
    224							child_cgroup_fd);
    225	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
    226		goto close_bpf_object;
    227	err = connect_send(CHILD_CGROUP);
    228	if (CHECK(err, "second-connect-send", "errno %d", errno))
    229		goto close_bpf_object;
    230	if (CHECK(obj->bss->invocations != 9,
    231		  "second-invoke", "invocations=%d", obj->bss->invocations))
    232		goto close_bpf_object;
    233	key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
    234	key.attach_type = BPF_CGROUP_INET_EGRESS;
    235	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
    236	if (assert_storage(obj->maps.cgroup_storage,
    237			   &key, &expected_cgroup_value))
    238		goto close_bpf_object;
    239	key.attach_type = BPF_CGROUP_INET_INGRESS;
    240	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
    241	if (assert_storage(obj->maps.cgroup_storage,
    242			   &key, &expected_cgroup_value))
    243		goto close_bpf_object;
    244	key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
    245	key.attach_type = BPF_CGROUP_INET_EGRESS;
    246	expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
    247	if (assert_storage(obj->maps.cgroup_storage,
    248			   &key, &expected_cgroup_value))
    249		goto close_bpf_object;
    250	key.attach_type = BPF_CGROUP_INET_INGRESS;
    251	expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
    252	if (assert_storage(obj->maps.cgroup_storage,
    253			   &key, &expected_cgroup_value))
    254		goto close_bpf_object;
    255
    256close_bpf_object:
    257	bpf_link__destroy(parent_egress1_link);
    258	bpf_link__destroy(parent_egress2_link);
    259	bpf_link__destroy(parent_ingress_link);
    260	bpf_link__destroy(child_egress1_link);
    261	bpf_link__destroy(child_egress2_link);
    262	bpf_link__destroy(child_ingress_link);
    263
    264	cg_storage_multi_isolated__destroy(obj);
    265}
    266
    267static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
    268{
    269	struct cg_storage_multi_shared *obj;
    270	struct cgroup_value expected_cgroup_value;
    271	__u64 key;
    272	struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
    273	struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
    274	struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
    275	bool err;
    276
    277	obj = cg_storage_multi_shared__open_and_load();
    278	if (CHECK(!obj, "skel-load", "errno %d", errno))
    279		return;
    280
    281	/* Attach to parent cgroup, trigger packet from child.
    282	 * Assert that there is three runs, two with parent cgroup egress and
    283	 * one with parent cgroup ingress.
    284	 * Also assert that child cgroup's storage does not exist
    285	 */
    286	parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
    287							 parent_cgroup_fd);
    288	if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
    289		goto close_bpf_object;
    290	parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
    291							 parent_cgroup_fd);
    292	if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
    293		goto close_bpf_object;
    294	parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
    295							 parent_cgroup_fd);
    296	if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
    297		goto close_bpf_object;
    298	err = connect_send(CHILD_CGROUP);
    299	if (CHECK(err, "first-connect-send", "errno %d", errno))
    300		goto close_bpf_object;
    301	if (CHECK(obj->bss->invocations != 3,
    302		  "first-invoke", "invocations=%d", obj->bss->invocations))
    303		goto close_bpf_object;
    304	key = get_cgroup_id(PARENT_CGROUP);
    305	expected_cgroup_value = (struct cgroup_value) {
    306		.egress_pkts = 2,
    307		.ingress_pkts = 1,
    308	};
    309	if (assert_storage(obj->maps.cgroup_storage,
    310			   &key, &expected_cgroup_value))
    311		goto close_bpf_object;
    312	key = get_cgroup_id(CHILD_CGROUP);
    313	if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
    314		goto close_bpf_object;
    315
    316	/* Attach to parent and child cgroup, trigger packet from child.
    317	 * Assert that there is six additional runs, parent cgroup egresses and
    318	 * ingress, child cgroup egresses and ingress.
    319	 */
    320	child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
    321							child_cgroup_fd);
    322	if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
    323		goto close_bpf_object;
    324	child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
    325							child_cgroup_fd);
    326	if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
    327		goto close_bpf_object;
    328	child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
    329							child_cgroup_fd);
    330	if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
    331		goto close_bpf_object;
    332	err = connect_send(CHILD_CGROUP);
    333	if (CHECK(err, "second-connect-send", "errno %d", errno))
    334		goto close_bpf_object;
    335	if (CHECK(obj->bss->invocations != 9,
    336		  "second-invoke", "invocations=%d", obj->bss->invocations))
    337		goto close_bpf_object;
    338	key = get_cgroup_id(PARENT_CGROUP);
    339	expected_cgroup_value = (struct cgroup_value) {
    340		.egress_pkts = 4,
    341		.ingress_pkts = 2,
    342	};
    343	if (assert_storage(obj->maps.cgroup_storage,
    344			   &key, &expected_cgroup_value))
    345		goto close_bpf_object;
    346	key = get_cgroup_id(CHILD_CGROUP);
    347	expected_cgroup_value = (struct cgroup_value) {
    348		.egress_pkts = 2,
    349		.ingress_pkts = 1,
    350	};
    351	if (assert_storage(obj->maps.cgroup_storage,
    352			   &key, &expected_cgroup_value))
    353		goto close_bpf_object;
    354
    355close_bpf_object:
    356	bpf_link__destroy(parent_egress1_link);
    357	bpf_link__destroy(parent_egress2_link);
    358	bpf_link__destroy(parent_ingress_link);
    359	bpf_link__destroy(child_egress1_link);
    360	bpf_link__destroy(child_egress2_link);
    361	bpf_link__destroy(child_ingress_link);
    362
    363	cg_storage_multi_shared__destroy(obj);
    364}
    365
    366void serial_test_cg_storage_multi(void)
    367{
    368	int parent_cgroup_fd = -1, child_cgroup_fd = -1;
    369
    370	parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
    371	if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
    372		goto close_cgroup_fd;
    373	child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
    374	if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
    375		goto close_cgroup_fd;
    376
    377	if (test__start_subtest("egress_only"))
    378		test_egress_only(parent_cgroup_fd, child_cgroup_fd);
    379
    380	if (test__start_subtest("isolated"))
    381		test_isolated(parent_cgroup_fd, child_cgroup_fd);
    382
    383	if (test__start_subtest("shared"))
    384		test_shared(parent_cgroup_fd, child_cgroup_fd);
    385
    386close_cgroup_fd:
    387	close(child_cgroup_fd);
    388	close(parent_cgroup_fd);
    389}