134b82d3aSKP Singh // SPDX-License-Identifier: GPL-2.0
234b82d3aSKP Singh 
334b82d3aSKP Singh /*
434b82d3aSKP Singh  * Copyright (C) 2020 Google LLC.
534b82d3aSKP Singh  */
634b82d3aSKP Singh 
734b82d3aSKP Singh #include <stdio.h>
834b82d3aSKP Singh #include <stdlib.h>
934b82d3aSKP Singh #include <unistd.h>
1034b82d3aSKP Singh #include <sys/wait.h>
1134b82d3aSKP Singh #include <test_progs.h>
12f446b570SKP Singh #include <linux/ring_buffer.h>
1334b82d3aSKP Singh 
1434b82d3aSKP Singh #include "ima.skel.h"
1534b82d3aSKP Singh 
1691e8fa25SRoberto Sassu #define MAX_SAMPLES 4
1727a77d0dSRoberto Sassu 
1891e8fa25SRoberto Sassu static int _run_measured_process(const char *measured_dir, u32 *monitored_pid,
1991e8fa25SRoberto Sassu 				 const char *cmd)
2034b82d3aSKP Singh {
2134b82d3aSKP Singh 	int child_pid, child_status;
2234b82d3aSKP Singh 
2334b82d3aSKP Singh 	child_pid = fork();
2434b82d3aSKP Singh 	if (child_pid == 0) {
2534b82d3aSKP Singh 		*monitored_pid = getpid();
2691e8fa25SRoberto Sassu 		execlp("./ima_setup.sh", "./ima_setup.sh", cmd, measured_dir,
2734b82d3aSKP Singh 		       NULL);
2834b82d3aSKP Singh 		exit(errno);
2934b82d3aSKP Singh 
3034b82d3aSKP Singh 	} else if (child_pid > 0) {
3134b82d3aSKP Singh 		waitpid(child_pid, &child_status, 0);
3234b82d3aSKP Singh 		return WEXITSTATUS(child_status);
3334b82d3aSKP Singh 	}
3434b82d3aSKP Singh 
3534b82d3aSKP Singh 	return -EINVAL;
3634b82d3aSKP Singh }
3734b82d3aSKP Singh 
3891e8fa25SRoberto Sassu static int run_measured_process(const char *measured_dir, u32 *monitored_pid)
3991e8fa25SRoberto Sassu {
4091e8fa25SRoberto Sassu 	return _run_measured_process(measured_dir, monitored_pid, "run");
4191e8fa25SRoberto Sassu }
4291e8fa25SRoberto Sassu 
4327a77d0dSRoberto Sassu static u64 ima_hash_from_bpf[MAX_SAMPLES];
4427a77d0dSRoberto Sassu static int ima_hash_from_bpf_idx;
45f446b570SKP Singh 
46f446b570SKP Singh static int process_sample(void *ctx, void *data, size_t len)
47f446b570SKP Singh {
4827a77d0dSRoberto Sassu 	if (ima_hash_from_bpf_idx >= MAX_SAMPLES)
4927a77d0dSRoberto Sassu 		return -ENOSPC;
5027a77d0dSRoberto Sassu 
5127a77d0dSRoberto Sassu 	ima_hash_from_bpf[ima_hash_from_bpf_idx++] = *((u64 *)data);
52f446b570SKP Singh 	return 0;
53f446b570SKP Singh }
54f446b570SKP Singh 
5527a77d0dSRoberto Sassu static void test_init(struct ima__bss *bss)
5627a77d0dSRoberto Sassu {
5727a77d0dSRoberto Sassu 	ima_hash_from_bpf_idx = 0;
5827a77d0dSRoberto Sassu 
5927a77d0dSRoberto Sassu 	bss->use_ima_file_hash = false;
6091e8fa25SRoberto Sassu 	bss->enable_bprm_creds_for_exec = false;
61*e6dcf7bbSRoberto Sassu 	bss->enable_kernel_read_file = false;
6227a77d0dSRoberto Sassu }
6327a77d0dSRoberto Sassu 
6434b82d3aSKP Singh void test_test_ima(void)
6534b82d3aSKP Singh {
6634b82d3aSKP Singh 	char measured_dir_template[] = "/tmp/ima_measuredXXXXXX";
67efadf2adSKumar Kartikeya Dwivedi 	struct ring_buffer *ringbuf = NULL;
6834b82d3aSKP Singh 	const char *measured_dir;
6991e8fa25SRoberto Sassu 	u64 bin_true_sample;
7034b82d3aSKP Singh 	char cmd[256];
7134b82d3aSKP Singh 
7234b82d3aSKP Singh 	int err, duration = 0;
7334b82d3aSKP Singh 	struct ima *skel = NULL;
7434b82d3aSKP Singh 
7534b82d3aSKP Singh 	skel = ima__open_and_load();
7634b82d3aSKP Singh 	if (CHECK(!skel, "skel_load", "skeleton failed\n"))
7734b82d3aSKP Singh 		goto close_prog;
7834b82d3aSKP Singh 
79f446b570SKP Singh 	ringbuf = ring_buffer__new(bpf_map__fd(skel->maps.ringbuf),
80f446b570SKP Singh 				   process_sample, NULL, NULL);
81f446b570SKP Singh 	if (!ASSERT_OK_PTR(ringbuf, "ringbuf"))
82f446b570SKP Singh 		goto close_prog;
83f446b570SKP Singh 
8434b82d3aSKP Singh 	err = ima__attach(skel);
8534b82d3aSKP Singh 	if (CHECK(err, "attach", "attach failed: %d\n", err))
8634b82d3aSKP Singh 		goto close_prog;
8734b82d3aSKP Singh 
8834b82d3aSKP Singh 	measured_dir = mkdtemp(measured_dir_template);
8934b82d3aSKP Singh 	if (CHECK(measured_dir == NULL, "mkdtemp", "err %d\n", errno))
9034b82d3aSKP Singh 		goto close_prog;
9134b82d3aSKP Singh 
9234b82d3aSKP Singh 	snprintf(cmd, sizeof(cmd), "./ima_setup.sh setup %s", measured_dir);
93cff90846SKP Singh 	err = system(cmd);
94cff90846SKP Singh 	if (CHECK(err, "failed to run command", "%s, errno = %d\n", cmd, errno))
9534b82d3aSKP Singh 		goto close_clean;
9634b82d3aSKP Singh 
9727a77d0dSRoberto Sassu 	/*
9827a77d0dSRoberto Sassu 	 * Test #1
9927a77d0dSRoberto Sassu 	 * - Goal: obtain a sample with the bpf_ima_inode_hash() helper
10027a77d0dSRoberto Sassu 	 * - Expected result:  1 sample (/bin/true)
10127a77d0dSRoberto Sassu 	 */
10227a77d0dSRoberto Sassu 	test_init(skel->bss);
10334b82d3aSKP Singh 	err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
10427a77d0dSRoberto Sassu 	if (CHECK(err, "run_measured_process #1", "err = %d\n", err))
10534b82d3aSKP Singh 		goto close_clean;
10634b82d3aSKP Singh 
107f446b570SKP Singh 	err = ring_buffer__consume(ringbuf);
108f446b570SKP Singh 	ASSERT_EQ(err, 1, "num_samples_or_err");
10927a77d0dSRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
11027a77d0dSRoberto Sassu 
11127a77d0dSRoberto Sassu 	/*
11227a77d0dSRoberto Sassu 	 * Test #2
11327a77d0dSRoberto Sassu 	 * - Goal: obtain samples with the bpf_ima_file_hash() helper
11427a77d0dSRoberto Sassu 	 * - Expected result: 2 samples (./ima_setup.sh, /bin/true)
11527a77d0dSRoberto Sassu 	 */
11627a77d0dSRoberto Sassu 	test_init(skel->bss);
11727a77d0dSRoberto Sassu 	skel->bss->use_ima_file_hash = true;
11827a77d0dSRoberto Sassu 	err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
11927a77d0dSRoberto Sassu 	if (CHECK(err, "run_measured_process #2", "err = %d\n", err))
12027a77d0dSRoberto Sassu 		goto close_clean;
12127a77d0dSRoberto Sassu 
12227a77d0dSRoberto Sassu 	err = ring_buffer__consume(ringbuf);
12327a77d0dSRoberto Sassu 	ASSERT_EQ(err, 2, "num_samples_or_err");
12427a77d0dSRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
12527a77d0dSRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
12691e8fa25SRoberto Sassu 	bin_true_sample = ima_hash_from_bpf[1];
12791e8fa25SRoberto Sassu 
12891e8fa25SRoberto Sassu 	/*
12991e8fa25SRoberto Sassu 	 * Test #3
13091e8fa25SRoberto Sassu 	 * - Goal: confirm that bpf_ima_inode_hash() returns a non-fresh digest
13191e8fa25SRoberto Sassu 	 * - Expected result: 2 samples (/bin/true: non-fresh, fresh)
13291e8fa25SRoberto Sassu 	 */
13391e8fa25SRoberto Sassu 	test_init(skel->bss);
13491e8fa25SRoberto Sassu 
13591e8fa25SRoberto Sassu 	err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
13691e8fa25SRoberto Sassu 				    "modify-bin");
13791e8fa25SRoberto Sassu 	if (CHECK(err, "modify-bin #3", "err = %d\n", err))
13891e8fa25SRoberto Sassu 		goto close_clean;
13991e8fa25SRoberto Sassu 
14091e8fa25SRoberto Sassu 	skel->bss->enable_bprm_creds_for_exec = true;
14191e8fa25SRoberto Sassu 	err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
14291e8fa25SRoberto Sassu 	if (CHECK(err, "run_measured_process #3", "err = %d\n", err))
14391e8fa25SRoberto Sassu 		goto close_clean;
14491e8fa25SRoberto Sassu 
14591e8fa25SRoberto Sassu 	err = ring_buffer__consume(ringbuf);
14691e8fa25SRoberto Sassu 	ASSERT_EQ(err, 2, "num_samples_or_err");
14791e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
14891e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
14991e8fa25SRoberto Sassu 	ASSERT_EQ(ima_hash_from_bpf[0], bin_true_sample, "sample_equal_or_err");
15091e8fa25SRoberto Sassu 	/* IMA refreshed the digest. */
15191e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[1], bin_true_sample,
15291e8fa25SRoberto Sassu 		   "sample_different_or_err");
15391e8fa25SRoberto Sassu 
15491e8fa25SRoberto Sassu 	/*
15591e8fa25SRoberto Sassu 	 * Test #4
15691e8fa25SRoberto Sassu 	 * - Goal: verify that bpf_ima_file_hash() returns a fresh digest
15791e8fa25SRoberto Sassu 	 * - Expected result: 4 samples (./ima_setup.sh: fresh, fresh;
15891e8fa25SRoberto Sassu 	 *                               /bin/true: fresh, fresh)
15991e8fa25SRoberto Sassu 	 */
16091e8fa25SRoberto Sassu 	test_init(skel->bss);
16191e8fa25SRoberto Sassu 	skel->bss->use_ima_file_hash = true;
16291e8fa25SRoberto Sassu 	skel->bss->enable_bprm_creds_for_exec = true;
16391e8fa25SRoberto Sassu 	err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
16491e8fa25SRoberto Sassu 	if (CHECK(err, "run_measured_process #4", "err = %d\n", err))
16591e8fa25SRoberto Sassu 		goto close_clean;
16691e8fa25SRoberto Sassu 
16791e8fa25SRoberto Sassu 	err = ring_buffer__consume(ringbuf);
16891e8fa25SRoberto Sassu 	ASSERT_EQ(err, 4, "num_samples_or_err");
16991e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
17091e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
17191e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[2], 0, "ima_hash");
17291e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[3], 0, "ima_hash");
17391e8fa25SRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[2], bin_true_sample,
17491e8fa25SRoberto Sassu 		   "sample_different_or_err");
17591e8fa25SRoberto Sassu 	ASSERT_EQ(ima_hash_from_bpf[3], ima_hash_from_bpf[2],
17691e8fa25SRoberto Sassu 		  "sample_equal_or_err");
17791e8fa25SRoberto Sassu 
17891e8fa25SRoberto Sassu 	skel->bss->use_ima_file_hash = false;
17991e8fa25SRoberto Sassu 	skel->bss->enable_bprm_creds_for_exec = false;
18091e8fa25SRoberto Sassu 	err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
18191e8fa25SRoberto Sassu 				    "restore-bin");
18291e8fa25SRoberto Sassu 	if (CHECK(err, "restore-bin #3", "err = %d\n", err))
18391e8fa25SRoberto Sassu 		goto close_clean;
18434b82d3aSKP Singh 
185*e6dcf7bbSRoberto Sassu 	/*
186*e6dcf7bbSRoberto Sassu 	 * Test #5
187*e6dcf7bbSRoberto Sassu 	 * - Goal: obtain a sample from the kernel_read_file hook
188*e6dcf7bbSRoberto Sassu 	 * - Expected result: 2 samples (./ima_setup.sh, policy_test)
189*e6dcf7bbSRoberto Sassu 	 */
190*e6dcf7bbSRoberto Sassu 	test_init(skel->bss);
191*e6dcf7bbSRoberto Sassu 	skel->bss->use_ima_file_hash = true;
192*e6dcf7bbSRoberto Sassu 	skel->bss->enable_kernel_read_file = true;
193*e6dcf7bbSRoberto Sassu 	err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
194*e6dcf7bbSRoberto Sassu 				    "load-policy");
195*e6dcf7bbSRoberto Sassu 	if (CHECK(err, "run_measured_process #5", "err = %d\n", err))
196*e6dcf7bbSRoberto Sassu 		goto close_clean;
197*e6dcf7bbSRoberto Sassu 
198*e6dcf7bbSRoberto Sassu 	err = ring_buffer__consume(ringbuf);
199*e6dcf7bbSRoberto Sassu 	ASSERT_EQ(err, 2, "num_samples_or_err");
200*e6dcf7bbSRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
201*e6dcf7bbSRoberto Sassu 	ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
202*e6dcf7bbSRoberto Sassu 
20334b82d3aSKP Singh close_clean:
20434b82d3aSKP Singh 	snprintf(cmd, sizeof(cmd), "./ima_setup.sh cleanup %s", measured_dir);
205cff90846SKP Singh 	err = system(cmd);
206cff90846SKP Singh 	CHECK(err, "failed to run command", "%s, errno = %d\n", cmd, errno);
20734b82d3aSKP Singh close_prog:
208efadf2adSKumar Kartikeya Dwivedi 	ring_buffer__free(ringbuf);
20934b82d3aSKP Singh 	ima__destroy(skel);
21034b82d3aSKP Singh }
211