1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
5 *
6 * Author: Roberto Sassu <roberto.sassu@huawei.com>
7 */
8
9 #include <stdio.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <endian.h>
14 #include <limits.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 #include <sys/mman.h>
18 #include <linux/keyctl.h>
19 #include <test_progs.h>
20
21 #include "test_verify_pkcs7_sig.skel.h"
22
23 #define MAX_DATA_SIZE (1024 * 1024)
24 #define MAX_SIG_SIZE 1024
25
26 #define VERIFY_USE_SECONDARY_KEYRING (1UL)
27 #define VERIFY_USE_PLATFORM_KEYRING (2UL)
28
29 /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
30 #define MODULE_SIG_STRING "~Module signature appended~\n"
31
32 /*
33 * Module signature information block.
34 *
35 * The constituents of the signature section are, in order:
36 *
37 * - Signer's name
38 * - Key identifier
39 * - Signature data
40 * - Information block
41 */
42 struct module_signature {
43 __u8 algo; /* Public-key crypto algorithm [0] */
44 __u8 hash; /* Digest algorithm [0] */
45 __u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
46 __u8 signer_len; /* Length of signer's name [0] */
47 __u8 key_id_len; /* Length of key identifier [0] */
48 __u8 __pad[3];
49 __be32 sig_len; /* Length of signature data */
50 };
51
52 struct data {
53 __u8 data[MAX_DATA_SIZE];
54 __u32 data_len;
55 __u8 sig[MAX_SIG_SIZE];
56 __u32 sig_len;
57 };
58
59 static bool kfunc_not_supported;
60
libbpf_print_cb(enum libbpf_print_level level,const char * fmt,va_list args)61 static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,
62 va_list args)
63 {
64 if (level == LIBBPF_WARN)
65 vprintf(fmt, args);
66
67 if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))
68 return 0;
69
70 if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature"))
71 return 0;
72
73 kfunc_not_supported = true;
74 return 0;
75 }
76
_run_setup_process(const char * setup_dir,const char * cmd)77 static int _run_setup_process(const char *setup_dir, const char *cmd)
78 {
79 int child_pid, child_status;
80
81 child_pid = fork();
82 if (child_pid == 0) {
83 execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,
84 setup_dir, NULL);
85 exit(errno);
86
87 } else if (child_pid > 0) {
88 waitpid(child_pid, &child_status, 0);
89 return WEXITSTATUS(child_status);
90 }
91
92 return -EINVAL;
93 }
94
populate_data_item_str(const char * tmp_dir,struct data * data_item)95 static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
96 {
97 struct stat st;
98 char data_template[] = "/tmp/dataXXXXXX";
99 char path[PATH_MAX];
100 int ret, fd, child_status, child_pid;
101
102 data_item->data_len = 4;
103 memcpy(data_item->data, "test", data_item->data_len);
104
105 fd = mkstemp(data_template);
106 if (fd == -1)
107 return -errno;
108
109 ret = write(fd, data_item->data, data_item->data_len);
110
111 close(fd);
112
113 if (ret != data_item->data_len) {
114 ret = -EIO;
115 goto out;
116 }
117
118 child_pid = fork();
119
120 if (child_pid == -1) {
121 ret = -errno;
122 goto out;
123 }
124
125 if (child_pid == 0) {
126 snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);
127
128 return execlp("./sign-file", "./sign-file", "-d", "sha256",
129 path, path, data_template, NULL);
130 }
131
132 waitpid(child_pid, &child_status, 0);
133
134 ret = WEXITSTATUS(child_status);
135 if (ret)
136 goto out;
137
138 snprintf(path, sizeof(path), "%s.p7s", data_template);
139
140 ret = stat(path, &st);
141 if (ret == -1) {
142 ret = -errno;
143 goto out;
144 }
145
146 if (st.st_size > sizeof(data_item->sig)) {
147 ret = -EINVAL;
148 goto out_sig;
149 }
150
151 data_item->sig_len = st.st_size;
152
153 fd = open(path, O_RDONLY);
154 if (fd == -1) {
155 ret = -errno;
156 goto out_sig;
157 }
158
159 ret = read(fd, data_item->sig, data_item->sig_len);
160
161 close(fd);
162
163 if (ret != data_item->sig_len) {
164 ret = -EIO;
165 goto out_sig;
166 }
167
168 ret = 0;
169 out_sig:
170 unlink(path);
171 out:
172 unlink(data_template);
173 return ret;
174 }
175
populate_data_item_mod(struct data * data_item)176 static int populate_data_item_mod(struct data *data_item)
177 {
178 char mod_path[PATH_MAX], *mod_path_ptr;
179 struct stat st;
180 void *mod;
181 FILE *fp;
182 struct module_signature ms;
183 int ret, fd, modlen, marker_len, sig_len;
184
185 data_item->data_len = 0;
186
187 if (stat("/lib/modules", &st) == -1)
188 return 0;
189
190 /* Requires CONFIG_TCP_CONG_BIC=m. */
191 fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r");
192 if (!fp)
193 return 0;
194
195 mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp);
196 pclose(fp);
197
198 if (!mod_path_ptr)
199 return 0;
200
201 mod_path_ptr = strchr(mod_path, '\n');
202 if (!mod_path_ptr)
203 return 0;
204
205 *mod_path_ptr = '\0';
206
207 if (stat(mod_path, &st) == -1)
208 return 0;
209
210 modlen = st.st_size;
211 marker_len = sizeof(MODULE_SIG_STRING) - 1;
212
213 fd = open(mod_path, O_RDONLY);
214 if (fd == -1)
215 return -errno;
216
217 mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
218
219 close(fd);
220
221 if (mod == MAP_FAILED)
222 return -errno;
223
224 if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) {
225 ret = -EINVAL;
226 goto out;
227 }
228
229 modlen -= marker_len;
230
231 memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
232
233 sig_len = __be32_to_cpu(ms.sig_len);
234 modlen -= sig_len + sizeof(ms);
235
236 if (modlen > sizeof(data_item->data)) {
237 ret = -E2BIG;
238 goto out;
239 }
240
241 memcpy(data_item->data, mod, modlen);
242 data_item->data_len = modlen;
243
244 if (sig_len > sizeof(data_item->sig)) {
245 ret = -E2BIG;
246 goto out;
247 }
248
249 memcpy(data_item->sig, mod + modlen, sig_len);
250 data_item->sig_len = sig_len;
251 ret = 0;
252 out:
253 munmap(mod, st.st_size);
254 return ret;
255 }
256
test_verify_pkcs7_sig(void)257 void test_verify_pkcs7_sig(void)
258 {
259 libbpf_print_fn_t old_print_cb;
260 char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
261 char *tmp_dir;
262 struct test_verify_pkcs7_sig *skel = NULL;
263 struct bpf_map *map;
264 struct data data;
265 int ret, zero = 0;
266
267 /* Trigger creation of session keyring. */
268 syscall(__NR_request_key, "keyring", "_uid.0", NULL,
269 KEY_SPEC_SESSION_KEYRING);
270
271 tmp_dir = mkdtemp(tmp_dir_template);
272 if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
273 return;
274
275 ret = _run_setup_process(tmp_dir, "setup");
276 if (!ASSERT_OK(ret, "_run_setup_process"))
277 goto close_prog;
278
279 skel = test_verify_pkcs7_sig__open();
280 if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))
281 goto close_prog;
282
283 old_print_cb = libbpf_set_print(libbpf_print_cb);
284 ret = test_verify_pkcs7_sig__load(skel);
285 libbpf_set_print(old_print_cb);
286
287 if (ret < 0 && kfunc_not_supported) {
288 printf(
289 "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",
290 __func__);
291 test__skip();
292 goto close_prog;
293 }
294
295 if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))
296 goto close_prog;
297
298 ret = test_verify_pkcs7_sig__attach(skel);
299 if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))
300 goto close_prog;
301
302 map = bpf_object__find_map_by_name(skel->obj, "data_input");
303 if (!ASSERT_OK_PTR(map, "data_input not found"))
304 goto close_prog;
305
306 skel->bss->monitored_pid = getpid();
307
308 /* Test without data and signature. */
309 skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
310
311 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
312 if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
313 goto close_prog;
314
315 /* Test successful signature verification with session keyring. */
316 ret = populate_data_item_str(tmp_dir, &data);
317 if (!ASSERT_OK(ret, "populate_data_item_str"))
318 goto close_prog;
319
320 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
321 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
322 goto close_prog;
323
324 /* Test successful signature verification with testing keyring. */
325 skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",
326 "ebpf_testing_keyring", NULL,
327 KEY_SPEC_SESSION_KEYRING);
328
329 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
330 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
331 goto close_prog;
332
333 /*
334 * Ensure key_task_permission() is called and rejects the keyring
335 * (no Search permission).
336 */
337 syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
338 0x37373737);
339
340 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
341 if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
342 goto close_prog;
343
344 syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
345 0x3f3f3f3f);
346
347 /*
348 * Ensure key_validate() is called and rejects the keyring (key expired)
349 */
350 syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT,
351 skel->bss->user_keyring_serial, 1);
352 sleep(1);
353
354 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
355 if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
356 goto close_prog;
357
358 skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
359
360 /* Test with corrupted data (signature verification should fail). */
361 data.data[0] = 'a';
362 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
363 if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
364 goto close_prog;
365
366 ret = populate_data_item_mod(&data);
367 if (!ASSERT_OK(ret, "populate_data_item_mod"))
368 goto close_prog;
369
370 /* Test signature verification with system keyrings. */
371 if (data.data_len) {
372 skel->bss->user_keyring_serial = 0;
373 skel->bss->system_keyring_id = 0;
374
375 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
376 BPF_ANY);
377 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
378 goto close_prog;
379
380 skel->bss->system_keyring_id = VERIFY_USE_SECONDARY_KEYRING;
381
382 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
383 BPF_ANY);
384 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
385 goto close_prog;
386
387 skel->bss->system_keyring_id = VERIFY_USE_PLATFORM_KEYRING;
388
389 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
390 BPF_ANY);
391 ASSERT_LT(ret, 0, "bpf_map_update_elem data_input");
392 }
393
394 close_prog:
395 _run_setup_process(tmp_dir, "cleanup");
396
397 if (!skel)
398 return;
399
400 skel->bss->monitored_pid = 0;
401 test_verify_pkcs7_sig__destroy(skel);
402 }
403