Linux Audio

Check our new training course

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