brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · ab0f02f Raw
566 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH5 *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 <sys/xattr.h>20#include <linux/fsverity.h>21#include <test_progs.h>22 23#include "test_verify_pkcs7_sig.skel.h"24#include "test_sig_in_xattr.skel.h"25 26#define MAX_DATA_SIZE (1024 * 1024)27#define MAX_SIG_SIZE 102428 29#define VERIFY_USE_SECONDARY_KEYRING (1UL)30#define VERIFY_USE_PLATFORM_KEYRING  (2UL)31 32#ifndef SHA256_DIGEST_SIZE33#define SHA256_DIGEST_SIZE      3234#endif35 36/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */37#define MODULE_SIG_STRING "~Module signature appended~\n"38 39/*40 * Module signature information block.41 *42 * The constituents of the signature section are, in order:43 *44 *	- Signer's name45 *	- Key identifier46 *	- Signature data47 *	- Information block48 */49struct module_signature {50	__u8	algo;		/* Public-key crypto algorithm [0] */51	__u8	hash;		/* Digest algorithm [0] */52	__u8	id_type;	/* Key identifier type [PKEY_ID_PKCS7] */53	__u8	signer_len;	/* Length of signer's name [0] */54	__u8	key_id_len;	/* Length of key identifier [0] */55	__u8	__pad[3];56	__be32	sig_len;	/* Length of signature data */57};58 59struct data {60	__u8 data[MAX_DATA_SIZE];61	__u32 data_len;62	__u8 sig[MAX_SIG_SIZE];63	__u32 sig_len;64};65 66static bool kfunc_not_supported;67 68static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,69			   va_list args)70{71	if (level == LIBBPF_WARN)72		vprintf(fmt, args);73 74	if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))75		return 0;76 77	if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature"))78		return 0;79 80	kfunc_not_supported = true;81	return 0;82}83 84static int _run_setup_process(const char *setup_dir, const char *cmd)85{86	int child_pid, child_status;87 88	child_pid = fork();89	if (child_pid == 0) {90		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,91		       setup_dir, NULL);92		exit(errno);93 94	} else if (child_pid > 0) {95		waitpid(child_pid, &child_status, 0);96		return WEXITSTATUS(child_status);97	}98 99	return -EINVAL;100}101 102static int populate_data_item_str(const char *tmp_dir, struct data *data_item)103{104	struct stat st;105	char data_template[] = "/tmp/dataXXXXXX";106	char path[PATH_MAX];107	int ret, fd, child_status, child_pid;108 109	data_item->data_len = 4;110	memcpy(data_item->data, "test", data_item->data_len);111 112	fd = mkstemp(data_template);113	if (fd == -1)114		return -errno;115 116	ret = write(fd, data_item->data, data_item->data_len);117 118	close(fd);119 120	if (ret != data_item->data_len) {121		ret = -EIO;122		goto out;123	}124 125	child_pid = fork();126 127	if (child_pid == -1) {128		ret = -errno;129		goto out;130	}131 132	if (child_pid == 0) {133		snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);134 135		return execlp("./sign-file", "./sign-file", "-d", "sha256",136			      path, path, data_template, NULL);137	}138 139	waitpid(child_pid, &child_status, 0);140 141	ret = WEXITSTATUS(child_status);142	if (ret)143		goto out;144 145	snprintf(path, sizeof(path), "%s.p7s", data_template);146 147	ret = stat(path, &st);148	if (ret == -1) {149		ret = -errno;150		goto out;151	}152 153	if (st.st_size > sizeof(data_item->sig)) {154		ret = -EINVAL;155		goto out_sig;156	}157 158	data_item->sig_len = st.st_size;159 160	fd = open(path, O_RDONLY);161	if (fd == -1) {162		ret = -errno;163		goto out_sig;164	}165 166	ret = read(fd, data_item->sig, data_item->sig_len);167 168	close(fd);169 170	if (ret != data_item->sig_len) {171		ret = -EIO;172		goto out_sig;173	}174 175	ret = 0;176out_sig:177	unlink(path);178out:179	unlink(data_template);180	return ret;181}182 183static int populate_data_item_mod(struct data *data_item)184{185	char mod_path[PATH_MAX], *mod_path_ptr;186	struct stat st;187	void *mod;188	FILE *fp;189	struct module_signature ms;190	int ret, fd, modlen, marker_len, sig_len;191 192	data_item->data_len = 0;193 194	if (stat("/lib/modules", &st) == -1)195		return 0;196 197	/* Requires CONFIG_TCP_CONG_BIC=m. */198	fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r");199	if (!fp)200		return 0;201 202	mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp);203	pclose(fp);204 205	if (!mod_path_ptr)206		return 0;207 208	mod_path_ptr = strchr(mod_path, '\n');209	if (!mod_path_ptr)210		return 0;211 212	*mod_path_ptr = '\0';213 214	if (stat(mod_path, &st) == -1)215		return 0;216 217	modlen = st.st_size;218	marker_len = sizeof(MODULE_SIG_STRING) - 1;219 220	fd = open(mod_path, O_RDONLY);221	if (fd == -1)222		return -errno;223 224	mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);225 226	close(fd);227 228	if (mod == MAP_FAILED)229		return -errno;230 231	if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) {232		ret = -EINVAL;233		goto out;234	}235 236	modlen -= marker_len;237 238	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));239 240	sig_len = __be32_to_cpu(ms.sig_len);241	modlen -= sig_len + sizeof(ms);242 243	if (modlen > sizeof(data_item->data)) {244		ret = -E2BIG;245		goto out;246	}247 248	memcpy(data_item->data, mod, modlen);249	data_item->data_len = modlen;250 251	if (sig_len > sizeof(data_item->sig)) {252		ret = -E2BIG;253		goto out;254	}255 256	memcpy(data_item->sig, mod + modlen, sig_len);257	data_item->sig_len = sig_len;258	ret = 0;259out:260	munmap(mod, st.st_size);261	return ret;262}263 264static void test_verify_pkcs7_sig_from_map(void)265{266	libbpf_print_fn_t old_print_cb;267	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";268	char *tmp_dir;269	struct test_verify_pkcs7_sig *skel = NULL;270	struct bpf_map *map;271	struct data data;272	int ret, zero = 0;273 274	/* Trigger creation of session keyring. */275	syscall(__NR_request_key, "keyring", "_uid.0", NULL,276		KEY_SPEC_SESSION_KEYRING);277 278	tmp_dir = mkdtemp(tmp_dir_template);279	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))280		return;281 282	ret = _run_setup_process(tmp_dir, "setup");283	if (!ASSERT_OK(ret, "_run_setup_process"))284		goto close_prog;285 286	skel = test_verify_pkcs7_sig__open();287	if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))288		goto close_prog;289 290	old_print_cb = libbpf_set_print(libbpf_print_cb);291	ret = test_verify_pkcs7_sig__load(skel);292	libbpf_set_print(old_print_cb);293 294	if (ret < 0 && kfunc_not_supported) {295		printf(296		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",297		  __func__);298		test__skip();299		goto close_prog;300	}301 302	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))303		goto close_prog;304 305	ret = test_verify_pkcs7_sig__attach(skel);306	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))307		goto close_prog;308 309	map = bpf_object__find_map_by_name(skel->obj, "data_input");310	if (!ASSERT_OK_PTR(map, "data_input not found"))311		goto close_prog;312 313	skel->bss->monitored_pid = getpid();314 315	/* Test without data and signature. */316	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;317 318	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);319	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))320		goto close_prog;321 322	/* Test successful signature verification with session keyring. */323	ret = populate_data_item_str(tmp_dir, &data);324	if (!ASSERT_OK(ret, "populate_data_item_str"))325		goto close_prog;326 327	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);328	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))329		goto close_prog;330 331	/* Test successful signature verification with testing keyring. */332	skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",333						 "ebpf_testing_keyring", NULL,334						 KEY_SPEC_SESSION_KEYRING);335 336	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);337	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))338		goto close_prog;339 340	/*341	 * Ensure key_task_permission() is called and rejects the keyring342	 * (no Search permission).343	 */344	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,345		0x37373737);346 347	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);348	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))349		goto close_prog;350 351	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,352		0x3f3f3f3f);353 354	/*355	 * Ensure key_validate() is called and rejects the keyring (key expired)356	 */357	syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT,358		skel->bss->user_keyring_serial, 1);359	sleep(1);360 361	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);362	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))363		goto close_prog;364 365	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;366 367	/* Test with corrupted data (signature verification should fail). */368	data.data[0] = 'a';369	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);370	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))371		goto close_prog;372 373	ret = populate_data_item_mod(&data);374	if (!ASSERT_OK(ret, "populate_data_item_mod"))375		goto close_prog;376 377	/* Test signature verification with system keyrings. */378	if (data.data_len) {379		skel->bss->user_keyring_serial = 0;380		skel->bss->system_keyring_id = 0;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_SECONDARY_KEYRING;388 389		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,390					  BPF_ANY);391		if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))392			goto close_prog;393 394		skel->bss->system_keyring_id = VERIFY_USE_PLATFORM_KEYRING;395 396		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,397					  BPF_ANY);398		ASSERT_LT(ret, 0, "bpf_map_update_elem data_input");399	}400 401close_prog:402	_run_setup_process(tmp_dir, "cleanup");403 404	if (!skel)405		return;406 407	skel->bss->monitored_pid = 0;408	test_verify_pkcs7_sig__destroy(skel);409}410 411static int get_signature_size(const char *sig_path)412{413	struct stat st;414 415	if (stat(sig_path, &st) == -1)416		return -1;417 418	return st.st_size;419}420 421static int add_signature_to_xattr(const char *data_path, const char *sig_path)422{423	char sig[MAX_SIG_SIZE] = {0};424	int fd, size, ret;425 426	if (sig_path) {427		fd = open(sig_path, O_RDONLY);428		if (fd < 0)429			return -1;430 431		size = read(fd, sig, MAX_SIG_SIZE);432		close(fd);433		if (size <= 0)434			return -1;435	} else {436		/* no sig_path, just write 32 bytes of zeros */437		size = 32;438	}439	ret = setxattr(data_path, "user.sig", sig, size, 0);440	if (!ASSERT_OK(ret, "setxattr"))441		return -1;442 443	return 0;444}445 446static int test_open_file(struct test_sig_in_xattr *skel, char *data_path,447			  pid_t pid, bool should_success, char *name)448{449	int ret;450 451	skel->bss->monitored_pid = pid;452	ret = open(data_path, O_RDONLY);453	close(ret);454	skel->bss->monitored_pid = 0;455 456	if (should_success) {457		if (!ASSERT_GE(ret, 0, name))458			return -1;459	} else {460		if (!ASSERT_LT(ret, 0, name))461			return -1;462	}463	return 0;464}465 466static void test_pkcs7_sig_fsverity(void)467{468	char data_path[PATH_MAX];469	char sig_path[PATH_MAX];470	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";471	char *tmp_dir;472	struct test_sig_in_xattr *skel = NULL;473	pid_t pid;474	int ret;475 476	tmp_dir = mkdtemp(tmp_dir_template);477	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))478		return;479 480	snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir);481	snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir);482 483	ret = _run_setup_process(tmp_dir, "setup");484	if (!ASSERT_OK(ret, "_run_setup_process"))485		goto out;486 487	ret = _run_setup_process(tmp_dir, "fsverity-create-sign");488 489	if (ret) {490		printf("%s: SKIP: fsverity [sign|enable] doesn't work.\n"491		       "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n",492		       __func__);493		test__skip();494		goto out;495	}496 497	skel = test_sig_in_xattr__open();498	if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open"))499		goto out;500	ret = get_signature_size(sig_path);501	if (!ASSERT_GT(ret, 0, "get_signature_size"))502		goto out;503	skel->bss->sig_size = ret;504	skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",505						 "ebpf_testing_keyring", NULL,506						 KEY_SPEC_SESSION_KEYRING);507	memcpy(skel->bss->digest, "FSVerity", 8);508 509	ret = test_sig_in_xattr__load(skel);510	if (!ASSERT_OK(ret, "test_sig_in_xattr__load"))511		goto out;512 513	ret = test_sig_in_xattr__attach(skel);514	if (!ASSERT_OK(ret, "test_sig_in_xattr__attach"))515		goto out;516 517	pid = getpid();518 519	/* Case 1: fsverity is not enabled, open should succeed */520	if (test_open_file(skel, data_path, pid, true, "open_1"))521		goto out;522 523	/* Case 2: fsverity is enabled, xattr is missing, open should524	 * fail525	 */526	ret = _run_setup_process(tmp_dir, "fsverity-enable");527	if (!ASSERT_OK(ret, "fsverity-enable"))528		goto out;529	if (test_open_file(skel, data_path, pid, false, "open_2"))530		goto out;531 532	/* Case 3: fsverity is enabled, xattr has valid signature, open533	 * should succeed534	 */535	ret = add_signature_to_xattr(data_path, sig_path);536	if (!ASSERT_OK(ret, "add_signature_to_xattr_1"))537		goto out;538 539	if (test_open_file(skel, data_path, pid, true, "open_3"))540		goto out;541 542	/* Case 4: fsverity is enabled, xattr has invalid signature, open543	 * should fail544	 */545	ret = add_signature_to_xattr(data_path, NULL);546	if (!ASSERT_OK(ret, "add_signature_to_xattr_2"))547		goto out;548	test_open_file(skel, data_path, pid, false, "open_4");549 550out:551	_run_setup_process(tmp_dir, "cleanup");552	if (!skel)553		return;554 555	skel->bss->monitored_pid = 0;556	test_sig_in_xattr__destroy(skel);557}558 559void test_verify_pkcs7_sig(void)560{561	if (test__start_subtest("pkcs7_sig_from_map"))562		test_verify_pkcs7_sig_from_map();563	if (test__start_subtest("pkcs7_sig_fsverity"))564		test_pkcs7_sig_fsverity();565}566