brintos

brintos / linux-shallow public Read only

0
0
Text · 17.2 KiB · 2bb5773 Raw
550 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 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#include "cgroup_getset_retval_hooks.skel.h"14 15#define SOL_CUSTOM	0xdeadbeef16 17static int zero;18 19static void test_setsockopt_set(int cgroup_fd, int sock_fd)20{21	struct cgroup_getset_retval_setsockopt *obj;22	struct bpf_link *link_set_eunatch = NULL;23 24	obj = cgroup_getset_retval_setsockopt__open_and_load();25	if (!ASSERT_OK_PTR(obj, "skel-load"))26		return;27 28	obj->bss->page_size = sysconf(_SC_PAGESIZE);29 30	/* Attach setsockopt that sets EUNATCH, assert that31	 * we actually get that error when we run setsockopt()32	 */33	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,34						      cgroup_fd);35	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))36		goto close_bpf_object;37 38	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,39				   &zero, sizeof(int)), "setsockopt"))40		goto close_bpf_object;41	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))42		goto close_bpf_object;43 44	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))45		goto close_bpf_object;46	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))47		goto close_bpf_object;48 49close_bpf_object:50	bpf_link__destroy(link_set_eunatch);51 52	cgroup_getset_retval_setsockopt__destroy(obj);53}54 55static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd)56{57	struct cgroup_getset_retval_setsockopt *obj;58	struct bpf_link *link_set_eunatch = NULL, *link_get_retval = NULL;59 60	obj = cgroup_getset_retval_setsockopt__open_and_load();61	if (!ASSERT_OK_PTR(obj, "skel-load"))62		return;63 64	obj->bss->page_size = sysconf(_SC_PAGESIZE);65 66	/* Attach setsockopt that sets EUNATCH, and one that gets the67	 * previously set errno. Assert that we get the same errno back.68	 */69	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,70						      cgroup_fd);71	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))72		goto close_bpf_object;73	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,74						     cgroup_fd);75	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))76		goto close_bpf_object;77 78	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,79				   &zero, sizeof(int)), "setsockopt"))80		goto close_bpf_object;81	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))82		goto close_bpf_object;83 84	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))85		goto close_bpf_object;86	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))87		goto close_bpf_object;88	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))89		goto close_bpf_object;90 91close_bpf_object:92	bpf_link__destroy(link_set_eunatch);93	bpf_link__destroy(link_get_retval);94 95	cgroup_getset_retval_setsockopt__destroy(obj);96}97 98static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd)99{100	struct cgroup_getset_retval_setsockopt *obj;101	struct bpf_link *link_get_retval = NULL;102 103	obj = cgroup_getset_retval_setsockopt__open_and_load();104	if (!ASSERT_OK_PTR(obj, "skel-load"))105		return;106 107	obj->bss->page_size = sysconf(_SC_PAGESIZE);108 109	/* Attach setsockopt that gets the previously set errno.110	 * Assert that, without anything setting one, we get 0.111	 */112	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,113						     cgroup_fd);114	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))115		goto close_bpf_object;116 117	if (!ASSERT_OK(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,118				  &zero, sizeof(int)), "setsockopt"))119		goto close_bpf_object;120 121	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))122		goto close_bpf_object;123	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))124		goto close_bpf_object;125	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))126		goto close_bpf_object;127 128close_bpf_object:129	bpf_link__destroy(link_get_retval);130 131	cgroup_getset_retval_setsockopt__destroy(obj);132}133 134static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd)135{136	struct cgroup_getset_retval_setsockopt *obj;137	struct bpf_link *link_get_retval = NULL, *link_set_eunatch = NULL;138 139	obj = cgroup_getset_retval_setsockopt__open_and_load();140	if (!ASSERT_OK_PTR(obj, "skel-load"))141		return;142 143	obj->bss->page_size = sysconf(_SC_PAGESIZE);144 145	/* Attach setsockopt that gets the previously set errno, and then146	 * one that sets the errno to EUNATCH. Assert that the get does not147	 * see EUNATCH set later, and does not prevent EUNATCH from being set.148	 */149	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,150						     cgroup_fd);151	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))152		goto close_bpf_object;153	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,154						      cgroup_fd);155	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))156		goto close_bpf_object;157 158	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,159				   &zero, sizeof(int)), "setsockopt"))160		goto close_bpf_object;161	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))162		goto close_bpf_object;163 164	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))165		goto close_bpf_object;166	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))167		goto close_bpf_object;168	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))169		goto close_bpf_object;170 171close_bpf_object:172	bpf_link__destroy(link_get_retval);173	bpf_link__destroy(link_set_eunatch);174 175	cgroup_getset_retval_setsockopt__destroy(obj);176}177 178static void test_setsockopt_override(int cgroup_fd, int sock_fd)179{180	struct cgroup_getset_retval_setsockopt *obj;181	struct bpf_link *link_set_eunatch = NULL, *link_set_eisconn = NULL;182	struct bpf_link *link_get_retval = NULL;183 184	obj = cgroup_getset_retval_setsockopt__open_and_load();185	if (!ASSERT_OK_PTR(obj, "skel-load"))186		return;187 188	obj->bss->page_size = sysconf(_SC_PAGESIZE);189 190	/* Attach setsockopt that sets EUNATCH, then one that sets EISCONN,191	 * and then one that gets the exported errno. Assert both the syscall192	 * and the helper sees the last set errno.193	 */194	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,195						      cgroup_fd);196	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))197		goto close_bpf_object;198	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,199						      cgroup_fd);200	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))201		goto close_bpf_object;202	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,203						     cgroup_fd);204	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))205		goto close_bpf_object;206 207	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,208				   &zero, sizeof(int)), "setsockopt"))209		goto close_bpf_object;210	if (!ASSERT_EQ(errno, EISCONN, "setsockopt-errno"))211		goto close_bpf_object;212 213	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))214		goto close_bpf_object;215	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))216		goto close_bpf_object;217	if (!ASSERT_EQ(obj->bss->retval_value, -EISCONN, "retval_value"))218		goto close_bpf_object;219 220close_bpf_object:221	bpf_link__destroy(link_set_eunatch);222	bpf_link__destroy(link_set_eisconn);223	bpf_link__destroy(link_get_retval);224 225	cgroup_getset_retval_setsockopt__destroy(obj);226}227 228static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd)229{230	struct cgroup_getset_retval_setsockopt *obj;231	struct bpf_link *link_legacy_eperm = NULL, *link_get_retval = NULL;232 233	obj = cgroup_getset_retval_setsockopt__open_and_load();234	if (!ASSERT_OK_PTR(obj, "skel-load"))235		return;236 237	obj->bss->page_size = sysconf(_SC_PAGESIZE);238 239	/* Attach setsockopt that return a reject without setting errno240	 * (legacy reject), and one that gets the errno. Assert that for241	 * backward compatibility the syscall result in EPERM, and this242	 * is also visible to the helper.243	 */244	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,245						       cgroup_fd);246	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))247		goto close_bpf_object;248	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,249						     cgroup_fd);250	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))251		goto close_bpf_object;252 253	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,254				   &zero, sizeof(int)), "setsockopt"))255		goto close_bpf_object;256	if (!ASSERT_EQ(errno, EPERM, "setsockopt-errno"))257		goto close_bpf_object;258 259	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))260		goto close_bpf_object;261	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))262		goto close_bpf_object;263	if (!ASSERT_EQ(obj->bss->retval_value, -EPERM, "retval_value"))264		goto close_bpf_object;265 266close_bpf_object:267	bpf_link__destroy(link_legacy_eperm);268	bpf_link__destroy(link_get_retval);269 270	cgroup_getset_retval_setsockopt__destroy(obj);271}272 273static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd)274{275	struct cgroup_getset_retval_setsockopt *obj;276	struct bpf_link *link_set_eunatch = NULL, *link_legacy_eperm = NULL;277	struct bpf_link *link_get_retval = NULL;278 279	obj = cgroup_getset_retval_setsockopt__open_and_load();280	if (!ASSERT_OK_PTR(obj, "skel-load"))281		return;282 283	obj->bss->page_size = sysconf(_SC_PAGESIZE);284 285	/* Attach setsockopt that sets EUNATCH, then one that return a reject286	 * without setting errno, and then one that gets the exported errno.287	 * Assert both the syscall and the helper's errno are unaffected by288	 * the second prog (i.e. legacy rejects does not override the errno289	 * to EPERM).290	 */291	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,292						      cgroup_fd);293	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))294		goto close_bpf_object;295	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,296						       cgroup_fd);297	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))298		goto close_bpf_object;299	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,300						     cgroup_fd);301	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))302		goto close_bpf_object;303 304	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,305				   &zero, sizeof(int)), "setsockopt"))306		goto close_bpf_object;307	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))308		goto close_bpf_object;309 310	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))311		goto close_bpf_object;312	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))313		goto close_bpf_object;314	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))315		goto close_bpf_object;316 317close_bpf_object:318	bpf_link__destroy(link_set_eunatch);319	bpf_link__destroy(link_legacy_eperm);320	bpf_link__destroy(link_get_retval);321 322	cgroup_getset_retval_setsockopt__destroy(obj);323}324 325static void test_getsockopt_get(int cgroup_fd, int sock_fd)326{327	struct cgroup_getset_retval_getsockopt *obj;328	struct bpf_link *link_get_retval = NULL;329	int buf;330	socklen_t optlen = sizeof(buf);331 332	obj = cgroup_getset_retval_getsockopt__open_and_load();333	if (!ASSERT_OK_PTR(obj, "skel-load"))334		return;335 336	obj->bss->page_size = sysconf(_SC_PAGESIZE);337 338	/* Attach getsockopt that gets previously set errno. Assert that the339	 * error from kernel is in both ctx_retval_value and retval_value.340	 */341	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,342						     cgroup_fd);343	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))344		goto close_bpf_object;345 346	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,347				   &buf, &optlen), "getsockopt"))348		goto close_bpf_object;349	if (!ASSERT_EQ(errno, EOPNOTSUPP, "getsockopt-errno"))350		goto close_bpf_object;351 352	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))353		goto close_bpf_object;354	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))355		goto close_bpf_object;356	if (!ASSERT_EQ(obj->bss->retval_value, -EOPNOTSUPP, "retval_value"))357		goto close_bpf_object;358	if (!ASSERT_EQ(obj->bss->ctx_retval_value, -EOPNOTSUPP, "ctx_retval_value"))359		goto close_bpf_object;360 361close_bpf_object:362	bpf_link__destroy(link_get_retval);363 364	cgroup_getset_retval_getsockopt__destroy(obj);365}366 367static void test_getsockopt_override(int cgroup_fd, int sock_fd)368{369	struct cgroup_getset_retval_getsockopt *obj;370	struct bpf_link *link_set_eisconn = NULL;371	int buf;372	socklen_t optlen = sizeof(buf);373 374	obj = cgroup_getset_retval_getsockopt__open_and_load();375	if (!ASSERT_OK_PTR(obj, "skel-load"))376		return;377 378	obj->bss->page_size = sysconf(_SC_PAGESIZE);379 380	/* Attach getsockopt that sets retval to -EISCONN. Assert that this381	 * overrides the value from kernel.382	 */383	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,384						      cgroup_fd);385	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))386		goto close_bpf_object;387 388	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,389				   &buf, &optlen), "getsockopt"))390		goto close_bpf_object;391	if (!ASSERT_EQ(errno, EISCONN, "getsockopt-errno"))392		goto close_bpf_object;393 394	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))395		goto close_bpf_object;396	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))397		goto close_bpf_object;398 399close_bpf_object:400	bpf_link__destroy(link_set_eisconn);401 402	cgroup_getset_retval_getsockopt__destroy(obj);403}404 405static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd)406{407	struct cgroup_getset_retval_getsockopt *obj;408	struct bpf_link *link_set_eisconn = NULL, *link_clear_retval = NULL;409	struct bpf_link *link_get_retval = NULL;410	int buf;411	socklen_t optlen = sizeof(buf);412 413	obj = cgroup_getset_retval_getsockopt__open_and_load();414	if (!ASSERT_OK_PTR(obj, "skel-load"))415		return;416 417	obj->bss->page_size = sysconf(_SC_PAGESIZE);418 419	/* Attach getsockopt that sets retval to -EISCONN, and one that clears420	 * ctx retval. Assert that the clearing ctx retval is synced to helper421	 * and clears any errors both from kernel and BPF..422	 */423	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,424						      cgroup_fd);425	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))426		goto close_bpf_object;427	link_clear_retval = bpf_program__attach_cgroup(obj->progs.clear_retval,428						       cgroup_fd);429	if (!ASSERT_OK_PTR(link_clear_retval, "cg-attach-clear_retval"))430		goto close_bpf_object;431	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,432						     cgroup_fd);433	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))434		goto close_bpf_object;435 436	if (!ASSERT_OK(getsockopt(sock_fd, SOL_CUSTOM, 0,437				  &buf, &optlen), "getsockopt"))438		goto close_bpf_object;439 440	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))441		goto close_bpf_object;442	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))443		goto close_bpf_object;444	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))445		goto close_bpf_object;446	if (!ASSERT_EQ(obj->bss->ctx_retval_value, 0, "ctx_retval_value"))447		goto close_bpf_object;448 449close_bpf_object:450	bpf_link__destroy(link_set_eisconn);451	bpf_link__destroy(link_clear_retval);452	bpf_link__destroy(link_get_retval);453 454	cgroup_getset_retval_getsockopt__destroy(obj);455}456 457struct exposed_hook {458	const char *name;459	int expected_err;460} exposed_hooks[] = {461 462#define BPF_RETVAL_HOOK(NAME, SECTION, CTX, EXPECTED_ERR) \463	{ \464		.name = #NAME, \465		.expected_err = EXPECTED_ERR, \466	},467 468#include "cgroup_getset_retval_hooks.h"469 470#undef BPF_RETVAL_HOOK471};472 473static void test_exposed_hooks(int cgroup_fd, int sock_fd)474{475	struct cgroup_getset_retval_hooks *skel;476	struct bpf_program *prog;477	int err;478	int i;479 480	for (i = 0; i < ARRAY_SIZE(exposed_hooks); i++) {481		skel = cgroup_getset_retval_hooks__open();482		if (!ASSERT_OK_PTR(skel, "cgroup_getset_retval_hooks__open"))483			continue;484 485		prog = bpf_object__find_program_by_name(skel->obj, exposed_hooks[i].name);486		if (!ASSERT_NEQ(prog, NULL, "bpf_object__find_program_by_name"))487			goto close_skel;488 489		err = bpf_program__set_autoload(prog, true);490		if (!ASSERT_OK(err, "bpf_program__set_autoload"))491			goto close_skel;492 493		err = cgroup_getset_retval_hooks__load(skel);494		ASSERT_EQ(err, exposed_hooks[i].expected_err, "expected_err");495 496close_skel:497		cgroup_getset_retval_hooks__destroy(skel);498	}499}500 501void test_cgroup_getset_retval(void)502{503	int cgroup_fd = -1;504	int sock_fd = -1;505 506	cgroup_fd = test__join_cgroup("/cgroup_getset_retval");507	if (!ASSERT_GE(cgroup_fd, 0, "cg-create"))508		goto close_fd;509 510	sock_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);511	if (!ASSERT_GE(sock_fd, 0, "start-server"))512		goto close_fd;513 514	if (test__start_subtest("setsockopt-set"))515		test_setsockopt_set(cgroup_fd, sock_fd);516 517	if (test__start_subtest("setsockopt-set_and_get"))518		test_setsockopt_set_and_get(cgroup_fd, sock_fd);519 520	if (test__start_subtest("setsockopt-default_zero"))521		test_setsockopt_default_zero(cgroup_fd, sock_fd);522 523	if (test__start_subtest("setsockopt-default_zero_and_set"))524		test_setsockopt_default_zero_and_set(cgroup_fd, sock_fd);525 526	if (test__start_subtest("setsockopt-override"))527		test_setsockopt_override(cgroup_fd, sock_fd);528 529	if (test__start_subtest("setsockopt-legacy_eperm"))530		test_setsockopt_legacy_eperm(cgroup_fd, sock_fd);531 532	if (test__start_subtest("setsockopt-legacy_no_override"))533		test_setsockopt_legacy_no_override(cgroup_fd, sock_fd);534 535	if (test__start_subtest("getsockopt-get"))536		test_getsockopt_get(cgroup_fd, sock_fd);537 538	if (test__start_subtest("getsockopt-override"))539		test_getsockopt_override(cgroup_fd, sock_fd);540 541	if (test__start_subtest("getsockopt-retval_sync"))542		test_getsockopt_retval_sync(cgroup_fd, sock_fd);543 544	if (test__start_subtest("exposed_hooks"))545		test_exposed_hooks(cgroup_fd, sock_fd);546 547close_fd:548	close(cgroup_fd);549}550