xref: /linux/tools/testing/selftests/bpf/prog_tests/cgroup_storage.c (revision aec2f682d47c54ef434b2d440992626d80b1ebdc)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <unistd.h>
4 #include <sys/socket.h>
5 #include <test_progs.h>
6 #include "cgroup_helpers.h"
7 #include "network_helpers.h"
8 #include "cgroup_storage.skel.h"
9 
10 #define TEST_CGROUP "/test-bpf-cgroup-storage-buf/"
11 #define TEST_NS "cgroup_storage_ns"
12 #define PING_CMD "ping localhost -c 1 -W 1 -q"
13 
14 static int setup_network(struct nstoken **token)
15 {
16 	SYS(fail, "ip netns add %s", TEST_NS);
17 	*token = open_netns(TEST_NS);
18 	if (!ASSERT_OK_PTR(*token, "open netns"))
19 		goto cleanup_ns;
20 	SYS(cleanup_ns, "ip link set lo up");
21 
22 	return 0;
23 
24 cleanup_ns:
25 	SYS_NOFAIL("ip netns del %s", TEST_NS);
26 fail:
27 	return -1;
28 }
29 
30 static void cleanup_network(struct nstoken *ns)
31 {
32 	close_netns(ns);
33 	SYS_NOFAIL("ip netns del %s", TEST_NS);
34 }
35 
36 void test_cgroup_storage(void)
37 {
38 	struct bpf_cgroup_storage_key key;
39 	struct cgroup_storage *skel;
40 	struct nstoken *ns = NULL;
41 	unsigned long long value;
42 	int cgroup_fd;
43 	int err;
44 
45 	cgroup_fd = cgroup_setup_and_join(TEST_CGROUP);
46 	if (!ASSERT_OK_FD(cgroup_fd, "create cgroup"))
47 		return;
48 
49 	if (!ASSERT_OK(setup_network(&ns), "setup network"))
50 		goto cleanup_cgroup;
51 
52 	skel = cgroup_storage__open_and_load();
53 	if (!ASSERT_OK_PTR(skel, "load program"))
54 		goto cleanup_network;
55 
56 	skel->links.bpf_prog =
57 		bpf_program__attach_cgroup(skel->progs.bpf_prog, cgroup_fd);
58 	if (!ASSERT_OK_PTR(skel->links.bpf_prog, "attach program"))
59 		goto cleanup_progs;
60 
61 	/* Check that one out of every two packets is dropped */
62 	err = SYS_NOFAIL(PING_CMD);
63 	ASSERT_OK(err, "first ping");
64 	err = SYS_NOFAIL(PING_CMD);
65 	ASSERT_NEQ(err, 0, "second ping");
66 	err = SYS_NOFAIL(PING_CMD);
67 	ASSERT_OK(err, "third ping");
68 
69 	err = bpf_map__get_next_key(skel->maps.cgroup_storage, NULL, &key,
70 				    sizeof(key));
71 	if (!ASSERT_OK(err, "get first key"))
72 		goto cleanup_progs;
73 	err = bpf_map__lookup_elem(skel->maps.cgroup_storage, &key, sizeof(key),
74 				   &value, sizeof(value), 0);
75 	if (!ASSERT_OK(err, "first packet count read"))
76 		goto cleanup_progs;
77 
78 	/* Add one to the packet counter, check again packet filtering */
79 	value++;
80 	err = bpf_map__update_elem(skel->maps.cgroup_storage, &key, sizeof(key),
81 				   &value, sizeof(value), 0);
82 	if (!ASSERT_OK(err, "increment packet counter"))
83 		goto cleanup_progs;
84 	err = SYS_NOFAIL(PING_CMD);
85 	ASSERT_OK(err, "fourth ping");
86 	err = SYS_NOFAIL(PING_CMD);
87 	ASSERT_NEQ(err, 0, "fifth ping");
88 	err = SYS_NOFAIL(PING_CMD);
89 	ASSERT_OK(err, "sixth ping");
90 
91 	err = bpf_map__get_next_key(skel->maps.cgroup_storage, &key, &key,
92 				    sizeof(key));
93 	ASSERT_ERR(err, "bpf_map__get_next_key should fail");
94 	ASSERT_EQ(errno, ENOENT, "no second key");
95 
96 cleanup_progs:
97 	cgroup_storage__destroy(skel);
98 cleanup_network:
99 	cleanup_network(ns);
100 cleanup_cgroup:
101 	close(cgroup_fd);
102 	cleanup_cgroup_environment();
103 }
104 
105 void test_cgroup_storage_oob(void)
106 {
107 	struct cgroup_storage *skel;
108 	int cgroup_fd, sock_fd;
109 
110 	cgroup_fd = cgroup_setup_and_join(TEST_CGROUP);
111 	if (!ASSERT_OK_FD(cgroup_fd, "create cgroup"))
112 		return;
113 
114 	/* Load and attach BPF program */
115 	skel = cgroup_storage__open_and_load();
116 	if (!ASSERT_OK_PTR(skel, "cgroup_storage__open_and_load"))
117 		goto cleanup_cgroup;
118 
119 	skel->links.trigger_oob = bpf_program__attach_cgroup(skel->progs.trigger_oob,
120 							      cgroup_fd);
121 	if (!ASSERT_OK_PTR(skel->links.trigger_oob, "attach_cgroup"))
122 		goto cleanup_skel;
123 
124 	/* Create a socket to trigger cgroup/sock_create hook.
125 	 * This will execute our BPF program and trigger the OOB read
126 	 * if the bug is present (before the fix).
127 	 */
128 	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
129 	if (!ASSERT_OK_FD(sock_fd, "create socket"))
130 		goto cleanup_skel;
131 
132 	close(sock_fd);
133 
134 	/* If we reach here without a kernel panic or KASAN report,
135 	 * the test passes (the fix is working).
136 	 */
137 
138 cleanup_skel:
139 	cgroup_storage__destroy(skel);
140 cleanup_cgroup:
141 	close(cgroup_fd);
142 	cleanup_cgroup_environment();
143 }
144