Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <stdlib.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <stdint.h>
7#include <sys/stat.h>
8#include <stdbool.h>
9#include <linux/bpf.h>
10#include <bpf/libbpf.h>
11#include <bpftool_helpers.h>
12#include <test_progs.h>
13#include <bpf/bpf.h>
14#include "security_bpf_map.skel.h"
15
16#define PROTECTED_MAP_NAME "prot_map"
17#define UNPROTECTED_MAP_NAME "not_prot_map"
18#define BPF_ITER_FILE "bpf_iter_map_elem.bpf.o"
19#define BPFFS_PIN_DIR "/sys/fs/bpf/test_bpftool_map"
20#define INNER_MAP_NAME "inner_map_tt"
21#define OUTER_MAP_NAME "outer_map_tt"
22
23#define MAP_NAME_MAX_LEN 64
24#define PATH_MAX_LEN 128
25
26enum map_protection {
27 PROTECTED,
28 UNPROTECTED
29};
30
31struct test_desc {
32 char *name;
33 enum map_protection protection;
34 struct bpf_map *map;
35 char *map_name;
36 bool pinned;
37 char pin_path[PATH_MAX_LEN];
38 bool write_must_fail;
39};
40
41static struct security_bpf_map *general_setup(void)
42{
43 struct security_bpf_map *skel;
44 uint32_t key, value;
45 int ret, i;
46
47 skel = security_bpf_map__open_and_load();
48 if (!ASSERT_OK_PTR(skel, "open and load skeleton"))
49 goto end;
50
51 struct bpf_map *maps[] = {skel->maps.prot_map, skel->maps.not_prot_map};
52
53 ret = security_bpf_map__attach(skel);
54 if (!ASSERT_OK(ret, "attach maps security programs"))
55 goto end_destroy;
56
57 for (i = 0; i < sizeof(maps)/sizeof(struct bpf_map *); i++) {
58 for (key = 0; key < 2; key++) {
59 int ret = bpf_map__update_elem(maps[i], &key,
60 sizeof(key), &key, sizeof(key),
61 0);
62 if (!ASSERT_OK(ret, "set initial map value"))
63 goto end_destroy;
64 }
65 }
66
67 key = 0;
68 value = 1;
69 ret = bpf_map__update_elem(skel->maps.prot_status_map, &key,
70 sizeof(key), &value, sizeof(value), 0);
71 if (!ASSERT_OK(ret, "configure map protection"))
72 goto end_destroy;
73
74 if (!ASSERT_OK(mkdir(BPFFS_PIN_DIR, S_IFDIR), "create bpffs pin dir"))
75 goto end_destroy;
76
77 return skel;
78end_destroy:
79 security_bpf_map__destroy(skel);
80end:
81 return NULL;
82}
83
84static void general_cleanup(struct security_bpf_map *skel)
85{
86 rmdir(BPFFS_PIN_DIR);
87 security_bpf_map__destroy(skel);
88}
89
90static void update_test_desc(struct security_bpf_map *skel,
91 struct test_desc *test)
92{
93 /* Now that the skeleton is loaded, update all missing fields to
94 * have the subtest properly configured
95 */
96 if (test->protection == PROTECTED) {
97 test->map = skel->maps.prot_map;
98 test->map_name = PROTECTED_MAP_NAME;
99 } else {
100 test->map = skel->maps.not_prot_map;
101 test->map_name = UNPROTECTED_MAP_NAME;
102 }
103}
104
105static int test_setup(struct security_bpf_map *skel, struct test_desc *desc)
106{
107 int ret;
108
109 update_test_desc(skel, desc);
110
111 if (desc->pinned) {
112 ret = snprintf(desc->pin_path, PATH_MAX_LEN, "%s/%s", BPFFS_PIN_DIR,
113 desc->name);
114 if (!ASSERT_GT(ret, 0, "format pin path"))
115 return 1;
116 ret = bpf_map__pin(desc->map, desc->pin_path);
117 if (!ASSERT_OK(ret, "pin map"))
118 return 1;
119 }
120
121 return 0;
122}
123
124static void test_cleanup(struct test_desc *desc)
125{
126 if (desc->pinned)
127 bpf_map__unpin(desc->map, NULL);
128}
129
130static int lookup_map_value(char *map_handle)
131{
132 char cmd[MAX_BPFTOOL_CMD_LEN];
133 int ret = 0;
134
135 ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "map lookup %s key 0 0 0 0",
136 map_handle);
137 if (!ASSERT_GT(ret, 0, "format map lookup cmd"))
138 return 1;
139 return run_bpftool_command(cmd);
140}
141
142static int read_map_btf_data(char *map_handle)
143{
144 char cmd[MAX_BPFTOOL_CMD_LEN];
145 int ret = 0;
146
147 ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "btf dump map %s",
148 map_handle);
149 if (!ASSERT_GT(ret, 0, "format map btf dump cmd"))
150 return 1;
151 return run_bpftool_command(cmd);
152}
153
154static int write_map_value(char *map_handle)
155{
156 char cmd[MAX_BPFTOOL_CMD_LEN];
157 int ret = 0;
158
159 ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN,
160 "map update %s key 0 0 0 0 value 1 1 1 1", map_handle);
161 if (!ASSERT_GT(ret, 0, "format value write cmd"))
162 return 1;
163 return run_bpftool_command(cmd);
164}
165
166static int delete_map_value(char *map_handle)
167{
168 char cmd[MAX_BPFTOOL_CMD_LEN];
169 int ret = 0;
170
171 ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN,
172 "map delete %s key 0 0 0 0", map_handle);
173 if (!ASSERT_GT(ret, 0, "format value deletion cmd"))
174 return 1;
175 return run_bpftool_command(cmd);
176}
177
178static int iterate_on_map_values(char *map_handle, char *iter_pin_path)
179{
180 char cmd[MAX_BPFTOOL_CMD_LEN];
181 int ret = 0;
182
183
184 ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "iter pin %s %s map %s",
185 BPF_ITER_FILE, iter_pin_path, map_handle);
186 if (!ASSERT_GT(ret, 0, "format iterator creation cmd"))
187 return 1;
188 ret = run_bpftool_command(cmd);
189 if (ret)
190 return ret;
191 ret = snprintf(cmd, MAP_NAME_MAX_LEN, "cat %s", iter_pin_path);
192 if (ret < 0)
193 goto cleanup;
194 ret = system(cmd);
195
196cleanup:
197 unlink(iter_pin_path);
198 return ret;
199}
200
201static int create_inner_map(void)
202{
203 char cmd[MAX_BPFTOOL_CMD_LEN];
204 int ret = 0;
205
206 ret = snprintf(
207 cmd, MAX_BPFTOOL_CMD_LEN,
208 "map create %s/%s type array key 4 value 4 entries 4 name %s",
209 BPFFS_PIN_DIR, INNER_MAP_NAME, INNER_MAP_NAME);
210 if (!ASSERT_GT(ret, 0, "format inner map create cmd"))
211 return 1;
212 return run_bpftool_command(cmd);
213}
214
215static int create_outer_map(void)
216{
217 char cmd[MAX_BPFTOOL_CMD_LEN];
218 int ret = 0;
219
220 ret = snprintf(
221 cmd, MAX_BPFTOOL_CMD_LEN,
222 "map create %s/%s type hash_of_maps key 4 value 4 entries 2 name %s inner_map name %s",
223 BPFFS_PIN_DIR, OUTER_MAP_NAME, OUTER_MAP_NAME, INNER_MAP_NAME);
224 if (!ASSERT_GT(ret, 0, "format outer map create cmd"))
225 return 1;
226 return run_bpftool_command(cmd);
227}
228
229static void delete_pinned_map(char *map_name)
230{
231 char pin_path[PATH_MAX_LEN];
232 int ret;
233
234 ret = snprintf(pin_path, PATH_MAX_LEN, "%s/%s", BPFFS_PIN_DIR,
235 map_name);
236 if (ret >= 0)
237 unlink(pin_path);
238}
239
240static int add_outer_map_entry(int key)
241{
242 char cmd[MAX_BPFTOOL_CMD_LEN];
243 int ret = 0;
244
245 ret = snprintf(
246 cmd, MAX_BPFTOOL_CMD_LEN,
247 "map update pinned %s/%s key %d 0 0 0 value name %s",
248 BPFFS_PIN_DIR, OUTER_MAP_NAME, key, INNER_MAP_NAME);
249 if (!ASSERT_GT(ret, 0, "format outer map value addition cmd"))
250 return 1;
251 return run_bpftool_command(cmd);
252}
253
254static void test_basic_access(struct test_desc *desc)
255{
256 char map_handle[MAP_NAME_MAX_LEN];
257 char iter_pin_path[PATH_MAX_LEN];
258 int ret;
259
260 if (desc->pinned)
261 ret = snprintf(map_handle, MAP_NAME_MAX_LEN, "pinned %s",
262 desc->pin_path);
263 else
264 ret = snprintf(map_handle, MAP_NAME_MAX_LEN, "name %s",
265 desc->map_name);
266 if (!ASSERT_GT(ret, 0, "format map handle"))
267 return;
268
269 ret = lookup_map_value(map_handle);
270 ASSERT_OK(ret, "read map value");
271
272 ret = read_map_btf_data(map_handle);
273 ASSERT_OK(ret, "read map btf data");
274
275 ret = write_map_value(map_handle);
276 ASSERT_OK(desc->write_must_fail ? !ret : ret, "write map value");
277
278 ret = delete_map_value(map_handle);
279 ASSERT_OK(desc->write_must_fail ? !ret : ret, "delete map value");
280 /* Restore deleted value */
281 if (!ret)
282 write_map_value(map_handle);
283
284 ret = snprintf(iter_pin_path, PATH_MAX_LEN, "%s/iter", BPFFS_PIN_DIR);
285 if (ASSERT_GT(ret, 0, "format iter pin path")) {
286 ret = iterate_on_map_values(map_handle, iter_pin_path);
287 ASSERT_OK(ret, "iterate on map values");
288 }
289}
290
291static void test_create_nested_maps(void)
292{
293 if (!ASSERT_OK(create_inner_map(), "create inner map"))
294 return;
295 if (!ASSERT_OK(create_outer_map(), "create outer map"))
296 goto end_cleanup_inner;
297 ASSERT_OK(add_outer_map_entry(0), "add a first entry in outer map");
298 ASSERT_OK(add_outer_map_entry(1), "add a second entry in outer map");
299 ASSERT_NEQ(add_outer_map_entry(2), 0, "add a third entry in outer map");
300
301 delete_pinned_map(OUTER_MAP_NAME);
302end_cleanup_inner:
303 delete_pinned_map(INNER_MAP_NAME);
304}
305
306static void test_btf_list(void)
307{
308 ASSERT_OK(run_bpftool_command("btf list"), "list btf data");
309}
310
311static struct test_desc tests[] = {
312 {
313 .name = "unprotected_unpinned",
314 .protection = UNPROTECTED,
315 .map_name = UNPROTECTED_MAP_NAME,
316 .pinned = false,
317 .write_must_fail = false,
318 },
319 {
320 .name = "unprotected_pinned",
321 .protection = UNPROTECTED,
322 .map_name = UNPROTECTED_MAP_NAME,
323 .pinned = true,
324 .write_must_fail = false,
325 },
326 {
327 .name = "protected_unpinned",
328 .protection = PROTECTED,
329 .map_name = UNPROTECTED_MAP_NAME,
330 .pinned = false,
331 .write_must_fail = true,
332 },
333 {
334 .name = "protected_pinned",
335 .protection = PROTECTED,
336 .map_name = UNPROTECTED_MAP_NAME,
337 .pinned = true,
338 .write_must_fail = true,
339 }
340};
341
342static const size_t tests_count = ARRAY_SIZE(tests);
343
344void test_bpftool_maps_access(void)
345{
346 struct security_bpf_map *skel;
347 struct test_desc *current;
348 int i;
349
350 skel = general_setup();
351 if (!ASSERT_OK_PTR(skel, "prepare programs"))
352 goto cleanup;
353
354 for (i = 0; i < tests_count; i++) {
355 current = &tests[i];
356 if (!test__start_subtest(current->name))
357 continue;
358 if (ASSERT_OK(test_setup(skel, current), "subtest setup")) {
359 test_basic_access(current);
360 test_cleanup(current);
361 }
362 }
363 if (test__start_subtest("nested_maps"))
364 test_create_nested_maps();
365 if (test__start_subtest("btf_list"))
366 test_btf_list();
367
368cleanup:
369 general_cleanup(skel);
370}
371