1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2021 Microsoft Corporation
4  *
5  * Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
6  *
7  * Measure critical data structures maintained by SELinux
8  * using IMA subsystem.
9  */
10 #include <linux/vmalloc.h>
11 #include <linux/ima.h>
12 #include "security.h"
13 #include "ima.h"
14 
15 /*
16  * selinux_ima_collect_state - Read selinux configuration settings
17  *
18  * On success returns the configuration settings string.
19  * On error, returns NULL.
20  */
selinux_ima_collect_state(void)21 static char *selinux_ima_collect_state(void)
22 {
23 	const char *on = "=1;", *off = "=0;";
24 	char *buf;
25 	int buf_len, len, i, rc;
26 
27 	buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
28 
29 	len = strlen(on);
30 	for (i = 0; i < __POLICYDB_CAP_MAX; i++)
31 		buf_len += strlen(selinux_policycap_names[i]) + len;
32 
33 	buf = kzalloc(buf_len, GFP_KERNEL);
34 	if (!buf)
35 		return NULL;
36 
37 	rc = strscpy(buf, "initialized", buf_len);
38 	WARN_ON(rc < 0);
39 
40 	rc = strlcat(buf, selinux_initialized() ? on : off, buf_len);
41 	WARN_ON(rc >= buf_len);
42 
43 	rc = strlcat(buf, "enforcing", buf_len);
44 	WARN_ON(rc >= buf_len);
45 
46 	rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len);
47 	WARN_ON(rc >= buf_len);
48 
49 	rc = strlcat(buf, "checkreqprot", buf_len);
50 	WARN_ON(rc >= buf_len);
51 
52 	rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len);
53 	WARN_ON(rc >= buf_len);
54 
55 	for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
56 		rc = strlcat(buf, selinux_policycap_names[i], buf_len);
57 		WARN_ON(rc >= buf_len);
58 
59 		rc = strlcat(buf, selinux_state.policycap[i] ? on : off,
60 			buf_len);
61 		WARN_ON(rc >= buf_len);
62 	}
63 
64 	return buf;
65 }
66 
67 /*
68  * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
69  */
selinux_ima_measure_state_locked(void)70 void selinux_ima_measure_state_locked(void)
71 {
72 	char *state_str = NULL;
73 	void *policy = NULL;
74 	size_t policy_len;
75 	int rc = 0;
76 
77 	lockdep_assert_held(&selinux_state.policy_mutex);
78 
79 	state_str = selinux_ima_collect_state();
80 	if (!state_str) {
81 		pr_err("SELinux: %s: failed to read state.\n", __func__);
82 		return;
83 	}
84 
85 	ima_measure_critical_data("selinux", "selinux-state",
86 				  state_str, strlen(state_str), false,
87 				  NULL, 0);
88 
89 	kfree(state_str);
90 
91 	/*
92 	 * Measure SELinux policy only after initialization is completed.
93 	 */
94 	if (!selinux_initialized())
95 		return;
96 
97 	rc = security_read_state_kernel(&policy, &policy_len);
98 	if (rc) {
99 		pr_err("SELinux: %s: failed to read policy %d.\n", __func__, rc);
100 		return;
101 	}
102 
103 	ima_measure_critical_data("selinux", "selinux-policy-hash",
104 				  policy, policy_len, true,
105 				  NULL, 0);
106 
107 	vfree(policy);
108 }
109 
110 /*
111  * selinux_ima_measure_state - Measure SELinux state and hash of policy
112  */
selinux_ima_measure_state(void)113 void selinux_ima_measure_state(void)
114 {
115 	lockdep_assert_not_held(&selinux_state.policy_mutex);
116 
117 	mutex_lock(&selinux_state.policy_mutex);
118 	selinux_ima_measure_state_locked();
119 	mutex_unlock(&selinux_state.policy_mutex);
120 }
121