xref: /linux/tools/testing/selftests/bpf/prog_tests/map_excl.c (revision 84f7a49e76ec8e0a1e18f3758e89800f8cf8cfc6)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2025 Google LLC. */
3 #define _GNU_SOURCE
4 #include <unistd.h>
5 #include <sys/syscall.h>
6 #include <test_progs.h>
7 #include <bpf/btf.h>
8 
9 #include "map_excl.skel.h"
10 #include "bpf_iter_bpf_array_map.skel.h"
11 
12 #ifndef SHA256_DIGEST_SIZE
13 #define SHA256_DIGEST_SIZE	32
14 #endif
15 
16 static void test_map_excl_allowed(void)
17 {
18 	struct map_excl *skel = map_excl__open();
19 	int err;
20 
21 	err = bpf_map__set_exclusive_program(skel->maps.excl_map, skel->progs.should_have_access);
22 	if (!ASSERT_OK(err, "bpf_map__set_exclusive_program"))
23 		goto out;
24 
25 	bpf_program__set_autoload(skel->progs.should_have_access, true);
26 	bpf_program__set_autoload(skel->progs.should_not_have_access, false);
27 
28 	err = map_excl__load(skel);
29 	ASSERT_OK(err, "map_excl__load");
30 out:
31 	map_excl__destroy(skel);
32 }
33 
34 static void test_map_excl_denied(void)
35 {
36 	struct map_excl *skel = map_excl__open();
37 	int err;
38 
39 	err = bpf_map__set_exclusive_program(skel->maps.excl_map, skel->progs.should_have_access);
40 	if (!ASSERT_OK(err, "bpf_map__make_exclusive"))
41 		goto out;
42 
43 	bpf_program__set_autoload(skel->progs.should_have_access, false);
44 	bpf_program__set_autoload(skel->progs.should_not_have_access, true);
45 
46 	err = map_excl__load(skel);
47 	ASSERT_EQ(err, -EACCES, "exclusive map access not denied\n");
48 out:
49 	map_excl__destroy(skel);
50 
51 }
52 
53 static void test_map_excl_no_map_in_map(void)
54 {
55 	__u8 hash[SHA256_DIGEST_SIZE] = {};
56 	LIBBPF_OPTS(bpf_map_create_opts, excl_opts,
57 		    .excl_prog_hash = hash,
58 		    .excl_prog_hash_size = sizeof(hash));
59 	LIBBPF_OPTS(bpf_map_create_opts, outer_opts);
60 	int excl_fd, tmpl_fd = -1, outer_fd = -1, err;
61 	__u32 key = 0;
62 
63 	excl_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl_inner", 4, 4, 1, &excl_opts);
64 	if (!ASSERT_OK_FD(excl_fd, "create exclusive map"))
65 		return;
66 
67 	outer_opts.inner_map_fd = excl_fd;
68 	err = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer_from_excl",
69 			     4, 4, 1, &outer_opts);
70 	if (err >= 0)
71 		close(err);
72 	ASSERT_EQ(err, -ENOTSUPP, "reject exclusive map as map-in-map template");
73 
74 	tmpl_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "tmpl", 4, 4, 1, NULL);
75 	if (!ASSERT_OK_FD(tmpl_fd, "create inner template"))
76 		goto out;
77 
78 	outer_opts.inner_map_fd = tmpl_fd;
79 	outer_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY_OF_MAPS, "outer", 4, 4, 1, &outer_opts);
80 	if (!ASSERT_OK_FD(outer_fd, "create map-of-maps"))
81 		goto out;
82 
83 	err = bpf_map_update_elem(outer_fd, &key, &excl_fd, 0);
84 	ASSERT_EQ(err, -ENOTSUPP, "reject exclusive map as map-in-map element");
85 out:
86 	if (outer_fd >= 0)
87 		close(outer_fd);
88 	if (tmpl_fd >= 0)
89 		close(tmpl_fd);
90 	close(excl_fd);
91 }
92 
93 static void test_map_excl_no_map_iter(void)
94 {
95 	__u8 hash[SHA256_DIGEST_SIZE] = {};
96 	LIBBPF_OPTS(bpf_map_create_opts, excl_opts,
97 		    .excl_prog_hash = hash,
98 		    .excl_prog_hash_size = sizeof(hash));
99 	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
100 	struct bpf_iter_bpf_array_map *skel = NULL;
101 	union bpf_iter_link_info linfo;
102 	struct bpf_link *link;
103 	int excl_fd;
104 
105 	excl_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl_iter", 4, 8, 3, &excl_opts);
106 	if (!ASSERT_OK_FD(excl_fd, "create exclusive map"))
107 		return;
108 
109 	skel = bpf_iter_bpf_array_map__open_and_load();
110 	if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_array_map__open_and_load"))
111 		goto out;
112 
113 	memset(&linfo, 0, sizeof(linfo));
114 	linfo.map.map_fd = excl_fd;
115 	opts.link_info = &linfo;
116 	opts.link_info_len = sizeof(linfo);
117 
118 	link = bpf_program__attach_iter(skel->progs.dump_bpf_array_map, &opts);
119 	if (!ASSERT_ERR_PTR(link, "reject exclusive map as iter target")) {
120 		bpf_link__destroy(link);
121 		goto out;
122 	}
123 	ASSERT_EQ(libbpf_get_error(link), -EPERM, "iter attach errno");
124 out:
125 	bpf_iter_bpf_array_map__destroy(skel);
126 	close(excl_fd);
127 }
128 
129 static void test_map_excl_create_validation(void)
130 {
131 	LIBBPF_OPTS(bpf_map_create_opts, o);
132 	__u8 hash[SHA256_DIGEST_SIZE] = {};
133 	int fd;
134 
135 	o.excl_prog_hash = hash;
136 	o.excl_prog_hash_size = SHA256_DIGEST_SIZE / 2;
137 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl", 4, 4, 1, &o);
138 	if (fd >= 0)
139 		close(fd);
140 	ASSERT_EQ(fd, -EINVAL, "reject short excl_prog_hash_size");
141 
142 	o.excl_prog_hash = hash;
143 	o.excl_prog_hash_size = SHA256_DIGEST_SIZE * 2;
144 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl", 4, 4, 1, &o);
145 	if (fd >= 0)
146 		close(fd);
147 	ASSERT_EQ(fd, -EINVAL, "reject long excl_prog_hash_size");
148 
149 	o.excl_prog_hash = hash;
150 	o.excl_prog_hash_size = 0;
151 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl", 4, 4, 1, &o);
152 	if (fd >= 0)
153 		close(fd);
154 	ASSERT_EQ(fd, -EINVAL, "reject hash pointer with zero size");
155 
156 	o.excl_prog_hash = NULL;
157 	o.excl_prog_hash_size = SHA256_DIGEST_SIZE;
158 	fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "excl", 4, 4, 1, &o);
159 	if (fd >= 0)
160 		close(fd);
161 	ASSERT_EQ(fd, -EINVAL, "reject size with NULL hash pointer");
162 }
163 
164 void test_map_excl(void)
165 {
166 	if (test__start_subtest("map_excl_allowed"))
167 		test_map_excl_allowed();
168 	if (test__start_subtest("map_excl_denied"))
169 		test_map_excl_denied();
170 	if (test__start_subtest("map_excl_no_map_in_map"))
171 		test_map_excl_no_map_in_map();
172 	if (test__start_subtest("map_excl_no_map_iter"))
173 		test_map_excl_no_map_iter();
174 	if (test__start_subtest("map_excl_create_validation"))
175 		test_map_excl_create_validation();
176 }
177