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

cgroup_getset_retval.c (15984B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3/*
      4 * Copyright 2021 Google LLC.
      5 */
      6
      7#include <test_progs.h>
      8#include <cgroup_helpers.h>
      9#include <network_helpers.h>
     10
     11#include "cgroup_getset_retval_setsockopt.skel.h"
     12#include "cgroup_getset_retval_getsockopt.skel.h"
     13
     14#define SOL_CUSTOM	0xdeadbeef
     15
     16static int zero;
     17
     18static void test_setsockopt_set(int cgroup_fd, int sock_fd)
     19{
     20	struct cgroup_getset_retval_setsockopt *obj;
     21	struct bpf_link *link_set_eunatch = NULL;
     22
     23	obj = cgroup_getset_retval_setsockopt__open_and_load();
     24	if (!ASSERT_OK_PTR(obj, "skel-load"))
     25		return;
     26
     27	/* Attach setsockopt that sets EUNATCH, assert that
     28	 * we actually get that error when we run setsockopt()
     29	 */
     30	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
     31						      cgroup_fd);
     32	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
     33		goto close_bpf_object;
     34
     35	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
     36				   &zero, sizeof(int)), "setsockopt"))
     37		goto close_bpf_object;
     38	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
     39		goto close_bpf_object;
     40
     41	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
     42		goto close_bpf_object;
     43	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
     44		goto close_bpf_object;
     45
     46close_bpf_object:
     47	bpf_link__destroy(link_set_eunatch);
     48
     49	cgroup_getset_retval_setsockopt__destroy(obj);
     50}
     51
     52static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd)
     53{
     54	struct cgroup_getset_retval_setsockopt *obj;
     55	struct bpf_link *link_set_eunatch = NULL, *link_get_retval = NULL;
     56
     57	obj = cgroup_getset_retval_setsockopt__open_and_load();
     58	if (!ASSERT_OK_PTR(obj, "skel-load"))
     59		return;
     60
     61	/* Attach setsockopt that sets EUNATCH, and one that gets the
     62	 * previously set errno. Assert that we get the same errno back.
     63	 */
     64	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
     65						      cgroup_fd);
     66	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
     67		goto close_bpf_object;
     68	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
     69						     cgroup_fd);
     70	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
     71		goto close_bpf_object;
     72
     73	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
     74				   &zero, sizeof(int)), "setsockopt"))
     75		goto close_bpf_object;
     76	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
     77		goto close_bpf_object;
     78
     79	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
     80		goto close_bpf_object;
     81	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
     82		goto close_bpf_object;
     83	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
     84		goto close_bpf_object;
     85
     86close_bpf_object:
     87	bpf_link__destroy(link_set_eunatch);
     88	bpf_link__destroy(link_get_retval);
     89
     90	cgroup_getset_retval_setsockopt__destroy(obj);
     91}
     92
     93static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd)
     94{
     95	struct cgroup_getset_retval_setsockopt *obj;
     96	struct bpf_link *link_get_retval = NULL;
     97
     98	obj = cgroup_getset_retval_setsockopt__open_and_load();
     99	if (!ASSERT_OK_PTR(obj, "skel-load"))
    100		return;
    101
    102	/* Attach setsockopt that gets the previously set errno.
    103	 * Assert that, without anything setting one, we get 0.
    104	 */
    105	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    106						     cgroup_fd);
    107	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    108		goto close_bpf_object;
    109
    110	if (!ASSERT_OK(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
    111				  &zero, sizeof(int)), "setsockopt"))
    112		goto close_bpf_object;
    113
    114	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
    115		goto close_bpf_object;
    116	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    117		goto close_bpf_object;
    118	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
    119		goto close_bpf_object;
    120
    121close_bpf_object:
    122	bpf_link__destroy(link_get_retval);
    123
    124	cgroup_getset_retval_setsockopt__destroy(obj);
    125}
    126
    127static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd)
    128{
    129	struct cgroup_getset_retval_setsockopt *obj;
    130	struct bpf_link *link_get_retval = NULL, *link_set_eunatch = NULL;
    131
    132	obj = cgroup_getset_retval_setsockopt__open_and_load();
    133	if (!ASSERT_OK_PTR(obj, "skel-load"))
    134		return;
    135
    136	/* Attach setsockopt that gets the previously set errno, and then
    137	 * one that sets the errno to EUNATCH. Assert that the get does not
    138	 * see EUNATCH set later, and does not prevent EUNATCH from being set.
    139	 */
    140	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    141						     cgroup_fd);
    142	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    143		goto close_bpf_object;
    144	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
    145						      cgroup_fd);
    146	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
    147		goto close_bpf_object;
    148
    149	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
    150				   &zero, sizeof(int)), "setsockopt"))
    151		goto close_bpf_object;
    152	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
    153		goto close_bpf_object;
    154
    155	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
    156		goto close_bpf_object;
    157	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    158		goto close_bpf_object;
    159	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
    160		goto close_bpf_object;
    161
    162close_bpf_object:
    163	bpf_link__destroy(link_get_retval);
    164	bpf_link__destroy(link_set_eunatch);
    165
    166	cgroup_getset_retval_setsockopt__destroy(obj);
    167}
    168
    169static void test_setsockopt_override(int cgroup_fd, int sock_fd)
    170{
    171	struct cgroup_getset_retval_setsockopt *obj;
    172	struct bpf_link *link_set_eunatch = NULL, *link_set_eisconn = NULL;
    173	struct bpf_link *link_get_retval = NULL;
    174
    175	obj = cgroup_getset_retval_setsockopt__open_and_load();
    176	if (!ASSERT_OK_PTR(obj, "skel-load"))
    177		return;
    178
    179	/* Attach setsockopt that sets EUNATCH, then one that sets EISCONN,
    180	 * and then one that gets the exported errno. Assert both the syscall
    181	 * and the helper sees the last set errno.
    182	 */
    183	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
    184						      cgroup_fd);
    185	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
    186		goto close_bpf_object;
    187	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
    188						      cgroup_fd);
    189	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
    190		goto close_bpf_object;
    191	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    192						     cgroup_fd);
    193	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    194		goto close_bpf_object;
    195
    196	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
    197				   &zero, sizeof(int)), "setsockopt"))
    198		goto close_bpf_object;
    199	if (!ASSERT_EQ(errno, EISCONN, "setsockopt-errno"))
    200		goto close_bpf_object;
    201
    202	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
    203		goto close_bpf_object;
    204	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    205		goto close_bpf_object;
    206	if (!ASSERT_EQ(obj->bss->retval_value, -EISCONN, "retval_value"))
    207		goto close_bpf_object;
    208
    209close_bpf_object:
    210	bpf_link__destroy(link_set_eunatch);
    211	bpf_link__destroy(link_set_eisconn);
    212	bpf_link__destroy(link_get_retval);
    213
    214	cgroup_getset_retval_setsockopt__destroy(obj);
    215}
    216
    217static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd)
    218{
    219	struct cgroup_getset_retval_setsockopt *obj;
    220	struct bpf_link *link_legacy_eperm = NULL, *link_get_retval = NULL;
    221
    222	obj = cgroup_getset_retval_setsockopt__open_and_load();
    223	if (!ASSERT_OK_PTR(obj, "skel-load"))
    224		return;
    225
    226	/* Attach setsockopt that return a reject without setting errno
    227	 * (legacy reject), and one that gets the errno. Assert that for
    228	 * backward compatibility the syscall result in EPERM, and this
    229	 * is also visible to the helper.
    230	 */
    231	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
    232						       cgroup_fd);
    233	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
    234		goto close_bpf_object;
    235	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    236						     cgroup_fd);
    237	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    238		goto close_bpf_object;
    239
    240	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
    241				   &zero, sizeof(int)), "setsockopt"))
    242		goto close_bpf_object;
    243	if (!ASSERT_EQ(errno, EPERM, "setsockopt-errno"))
    244		goto close_bpf_object;
    245
    246	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
    247		goto close_bpf_object;
    248	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    249		goto close_bpf_object;
    250	if (!ASSERT_EQ(obj->bss->retval_value, -EPERM, "retval_value"))
    251		goto close_bpf_object;
    252
    253close_bpf_object:
    254	bpf_link__destroy(link_legacy_eperm);
    255	bpf_link__destroy(link_get_retval);
    256
    257	cgroup_getset_retval_setsockopt__destroy(obj);
    258}
    259
    260static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd)
    261{
    262	struct cgroup_getset_retval_setsockopt *obj;
    263	struct bpf_link *link_set_eunatch = NULL, *link_legacy_eperm = NULL;
    264	struct bpf_link *link_get_retval = NULL;
    265
    266	obj = cgroup_getset_retval_setsockopt__open_and_load();
    267	if (!ASSERT_OK_PTR(obj, "skel-load"))
    268		return;
    269
    270	/* Attach setsockopt that sets EUNATCH, then one that return a reject
    271	 * without setting errno, and then one that gets the exported errno.
    272	 * Assert both the syscall and the helper's errno are unaffected by
    273	 * the second prog (i.e. legacy rejects does not override the errno
    274	 * to EPERM).
    275	 */
    276	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
    277						      cgroup_fd);
    278	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
    279		goto close_bpf_object;
    280	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
    281						       cgroup_fd);
    282	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
    283		goto close_bpf_object;
    284	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    285						     cgroup_fd);
    286	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    287		goto close_bpf_object;
    288
    289	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
    290				   &zero, sizeof(int)), "setsockopt"))
    291		goto close_bpf_object;
    292	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
    293		goto close_bpf_object;
    294
    295	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
    296		goto close_bpf_object;
    297	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    298		goto close_bpf_object;
    299	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
    300		goto close_bpf_object;
    301
    302close_bpf_object:
    303	bpf_link__destroy(link_set_eunatch);
    304	bpf_link__destroy(link_legacy_eperm);
    305	bpf_link__destroy(link_get_retval);
    306
    307	cgroup_getset_retval_setsockopt__destroy(obj);
    308}
    309
    310static void test_getsockopt_get(int cgroup_fd, int sock_fd)
    311{
    312	struct cgroup_getset_retval_getsockopt *obj;
    313	struct bpf_link *link_get_retval = NULL;
    314	int buf;
    315	socklen_t optlen = sizeof(buf);
    316
    317	obj = cgroup_getset_retval_getsockopt__open_and_load();
    318	if (!ASSERT_OK_PTR(obj, "skel-load"))
    319		return;
    320
    321	/* Attach getsockopt that gets previously set errno. Assert that the
    322	 * error from kernel is in both ctx_retval_value and retval_value.
    323	 */
    324	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    325						     cgroup_fd);
    326	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    327		goto close_bpf_object;
    328
    329	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
    330				   &buf, &optlen), "getsockopt"))
    331		goto close_bpf_object;
    332	if (!ASSERT_EQ(errno, EOPNOTSUPP, "getsockopt-errno"))
    333		goto close_bpf_object;
    334
    335	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
    336		goto close_bpf_object;
    337	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    338		goto close_bpf_object;
    339	if (!ASSERT_EQ(obj->bss->retval_value, -EOPNOTSUPP, "retval_value"))
    340		goto close_bpf_object;
    341	if (!ASSERT_EQ(obj->bss->ctx_retval_value, -EOPNOTSUPP, "ctx_retval_value"))
    342		goto close_bpf_object;
    343
    344close_bpf_object:
    345	bpf_link__destroy(link_get_retval);
    346
    347	cgroup_getset_retval_getsockopt__destroy(obj);
    348}
    349
    350static void test_getsockopt_override(int cgroup_fd, int sock_fd)
    351{
    352	struct cgroup_getset_retval_getsockopt *obj;
    353	struct bpf_link *link_set_eisconn = NULL;
    354	int buf;
    355	socklen_t optlen = sizeof(buf);
    356
    357	obj = cgroup_getset_retval_getsockopt__open_and_load();
    358	if (!ASSERT_OK_PTR(obj, "skel-load"))
    359		return;
    360
    361	/* Attach getsockopt that sets retval to -EISCONN. Assert that this
    362	 * overrides the value from kernel.
    363	 */
    364	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
    365						      cgroup_fd);
    366	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
    367		goto close_bpf_object;
    368
    369	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
    370				   &buf, &optlen), "getsockopt"))
    371		goto close_bpf_object;
    372	if (!ASSERT_EQ(errno, EISCONN, "getsockopt-errno"))
    373		goto close_bpf_object;
    374
    375	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
    376		goto close_bpf_object;
    377	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    378		goto close_bpf_object;
    379
    380close_bpf_object:
    381	bpf_link__destroy(link_set_eisconn);
    382
    383	cgroup_getset_retval_getsockopt__destroy(obj);
    384}
    385
    386static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd)
    387{
    388	struct cgroup_getset_retval_getsockopt *obj;
    389	struct bpf_link *link_set_eisconn = NULL, *link_clear_retval = NULL;
    390	struct bpf_link *link_get_retval = NULL;
    391	int buf;
    392	socklen_t optlen = sizeof(buf);
    393
    394	obj = cgroup_getset_retval_getsockopt__open_and_load();
    395	if (!ASSERT_OK_PTR(obj, "skel-load"))
    396		return;
    397
    398	/* Attach getsockopt that sets retval to -EISCONN, and one that clears
    399	 * ctx retval. Assert that the clearing ctx retval is synced to helper
    400	 * and clears any errors both from kernel and BPF..
    401	 */
    402	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
    403						      cgroup_fd);
    404	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
    405		goto close_bpf_object;
    406	link_clear_retval = bpf_program__attach_cgroup(obj->progs.clear_retval,
    407						       cgroup_fd);
    408	if (!ASSERT_OK_PTR(link_clear_retval, "cg-attach-clear_retval"))
    409		goto close_bpf_object;
    410	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
    411						     cgroup_fd);
    412	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
    413		goto close_bpf_object;
    414
    415	if (!ASSERT_OK(getsockopt(sock_fd, SOL_CUSTOM, 0,
    416				  &buf, &optlen), "getsockopt"))
    417		goto close_bpf_object;
    418
    419	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
    420		goto close_bpf_object;
    421	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
    422		goto close_bpf_object;
    423	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
    424		goto close_bpf_object;
    425	if (!ASSERT_EQ(obj->bss->ctx_retval_value, 0, "ctx_retval_value"))
    426		goto close_bpf_object;
    427
    428close_bpf_object:
    429	bpf_link__destroy(link_set_eisconn);
    430	bpf_link__destroy(link_clear_retval);
    431	bpf_link__destroy(link_get_retval);
    432
    433	cgroup_getset_retval_getsockopt__destroy(obj);
    434}
    435
    436void test_cgroup_getset_retval(void)
    437{
    438	int cgroup_fd = -1;
    439	int sock_fd = -1;
    440
    441	cgroup_fd = test__join_cgroup("/cgroup_getset_retval");
    442	if (!ASSERT_GE(cgroup_fd, 0, "cg-create"))
    443		goto close_fd;
    444
    445	sock_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
    446	if (!ASSERT_GE(sock_fd, 0, "start-server"))
    447		goto close_fd;
    448
    449	if (test__start_subtest("setsockopt-set"))
    450		test_setsockopt_set(cgroup_fd, sock_fd);
    451
    452	if (test__start_subtest("setsockopt-set_and_get"))
    453		test_setsockopt_set_and_get(cgroup_fd, sock_fd);
    454
    455	if (test__start_subtest("setsockopt-default_zero"))
    456		test_setsockopt_default_zero(cgroup_fd, sock_fd);
    457
    458	if (test__start_subtest("setsockopt-default_zero_and_set"))
    459		test_setsockopt_default_zero_and_set(cgroup_fd, sock_fd);
    460
    461	if (test__start_subtest("setsockopt-override"))
    462		test_setsockopt_override(cgroup_fd, sock_fd);
    463
    464	if (test__start_subtest("setsockopt-legacy_eperm"))
    465		test_setsockopt_legacy_eperm(cgroup_fd, sock_fd);
    466
    467	if (test__start_subtest("setsockopt-legacy_no_override"))
    468		test_setsockopt_legacy_no_override(cgroup_fd, sock_fd);
    469
    470	if (test__start_subtest("getsockopt-get"))
    471		test_getsockopt_get(cgroup_fd, sock_fd);
    472
    473	if (test__start_subtest("getsockopt-override"))
    474		test_getsockopt_override(cgroup_fd, sock_fd);
    475
    476	if (test__start_subtest("getsockopt-retval_sync"))
    477		test_getsockopt_retval_sync(cgroup_fd, sock_fd);
    478
    479close_fd:
    480	close(cgroup_fd);
    481}