xref: /openbmc/linux/security/selinux/ima.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1fdd1ffe8SLakshmi Ramasubramanian // SPDX-License-Identifier: GPL-2.0+
2fdd1ffe8SLakshmi Ramasubramanian /*
3fdd1ffe8SLakshmi Ramasubramanian  * Copyright (C) 2021 Microsoft Corporation
4fdd1ffe8SLakshmi Ramasubramanian  *
5fdd1ffe8SLakshmi Ramasubramanian  * Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
6fdd1ffe8SLakshmi Ramasubramanian  *
7fdd1ffe8SLakshmi Ramasubramanian  * Measure critical data structures maintained by SELinux
8fdd1ffe8SLakshmi Ramasubramanian  * using IMA subsystem.
9fdd1ffe8SLakshmi Ramasubramanian  */
10fdd1ffe8SLakshmi Ramasubramanian #include <linux/vmalloc.h>
11fdd1ffe8SLakshmi Ramasubramanian #include <linux/ima.h>
12fdd1ffe8SLakshmi Ramasubramanian #include "security.h"
13fdd1ffe8SLakshmi Ramasubramanian #include "ima.h"
14fdd1ffe8SLakshmi Ramasubramanian 
15fdd1ffe8SLakshmi Ramasubramanian /*
162554a48fSLakshmi Ramasubramanian  * selinux_ima_collect_state - Read selinux configuration settings
172554a48fSLakshmi Ramasubramanian  *
182554a48fSLakshmi Ramasubramanian  * On success returns the configuration settings string.
192554a48fSLakshmi Ramasubramanian  * On error, returns NULL.
202554a48fSLakshmi Ramasubramanian  */
selinux_ima_collect_state(void)21*e67b7985SStephen Smalley static char *selinux_ima_collect_state(void)
222554a48fSLakshmi Ramasubramanian {
232554a48fSLakshmi Ramasubramanian 	const char *on = "=1;", *off = "=0;";
242554a48fSLakshmi Ramasubramanian 	char *buf;
252554a48fSLakshmi Ramasubramanian 	int buf_len, len, i, rc;
262554a48fSLakshmi Ramasubramanian 
272554a48fSLakshmi Ramasubramanian 	buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
282554a48fSLakshmi Ramasubramanian 
292554a48fSLakshmi Ramasubramanian 	len = strlen(on);
30cdbec3edSPaul Moore 	for (i = 0; i < __POLICYDB_CAP_MAX; i++)
312554a48fSLakshmi Ramasubramanian 		buf_len += strlen(selinux_policycap_names[i]) + len;
322554a48fSLakshmi Ramasubramanian 
332554a48fSLakshmi Ramasubramanian 	buf = kzalloc(buf_len, GFP_KERNEL);
342554a48fSLakshmi Ramasubramanian 	if (!buf)
352554a48fSLakshmi Ramasubramanian 		return NULL;
362554a48fSLakshmi Ramasubramanian 
372554a48fSLakshmi Ramasubramanian 	rc = strscpy(buf, "initialized", buf_len);
382554a48fSLakshmi Ramasubramanian 	WARN_ON(rc < 0);
392554a48fSLakshmi Ramasubramanian 
40*e67b7985SStephen Smalley 	rc = strlcat(buf, selinux_initialized() ? on : off, buf_len);
412554a48fSLakshmi Ramasubramanian 	WARN_ON(rc >= buf_len);
422554a48fSLakshmi Ramasubramanian 
432554a48fSLakshmi Ramasubramanian 	rc = strlcat(buf, "enforcing", buf_len);
442554a48fSLakshmi Ramasubramanian 	WARN_ON(rc >= buf_len);
452554a48fSLakshmi Ramasubramanian 
46*e67b7985SStephen Smalley 	rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len);
472554a48fSLakshmi Ramasubramanian 	WARN_ON(rc >= buf_len);
482554a48fSLakshmi Ramasubramanian 
492554a48fSLakshmi Ramasubramanian 	rc = strlcat(buf, "checkreqprot", buf_len);
502554a48fSLakshmi Ramasubramanian 	WARN_ON(rc >= buf_len);
512554a48fSLakshmi Ramasubramanian 
52*e67b7985SStephen Smalley 	rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len);
532554a48fSLakshmi Ramasubramanian 	WARN_ON(rc >= buf_len);
542554a48fSLakshmi Ramasubramanian 
55cdbec3edSPaul Moore 	for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
562554a48fSLakshmi Ramasubramanian 		rc = strlcat(buf, selinux_policycap_names[i], buf_len);
572554a48fSLakshmi Ramasubramanian 		WARN_ON(rc >= buf_len);
582554a48fSLakshmi Ramasubramanian 
59*e67b7985SStephen Smalley 		rc = strlcat(buf, selinux_state.policycap[i] ? on : off,
60*e67b7985SStephen Smalley 			buf_len);
612554a48fSLakshmi Ramasubramanian 		WARN_ON(rc >= buf_len);
622554a48fSLakshmi Ramasubramanian 	}
632554a48fSLakshmi Ramasubramanian 
642554a48fSLakshmi Ramasubramanian 	return buf;
652554a48fSLakshmi Ramasubramanian }
662554a48fSLakshmi Ramasubramanian 
672554a48fSLakshmi Ramasubramanian /*
682554a48fSLakshmi Ramasubramanian  * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
69fdd1ffe8SLakshmi Ramasubramanian  */
selinux_ima_measure_state_locked(void)70*e67b7985SStephen Smalley void selinux_ima_measure_state_locked(void)
71fdd1ffe8SLakshmi Ramasubramanian {
722554a48fSLakshmi Ramasubramanian 	char *state_str = NULL;
73fdd1ffe8SLakshmi Ramasubramanian 	void *policy = NULL;
74fdd1ffe8SLakshmi Ramasubramanian 	size_t policy_len;
75fdd1ffe8SLakshmi Ramasubramanian 	int rc = 0;
76fdd1ffe8SLakshmi Ramasubramanian 
77*e67b7985SStephen Smalley 	lockdep_assert_held(&selinux_state.policy_mutex);
782554a48fSLakshmi Ramasubramanian 
79*e67b7985SStephen Smalley 	state_str = selinux_ima_collect_state();
802554a48fSLakshmi Ramasubramanian 	if (!state_str) {
812554a48fSLakshmi Ramasubramanian 		pr_err("SELinux: %s: failed to read state.\n", __func__);
822554a48fSLakshmi Ramasubramanian 		return;
832554a48fSLakshmi Ramasubramanian 	}
842554a48fSLakshmi Ramasubramanian 
852554a48fSLakshmi Ramasubramanian 	ima_measure_critical_data("selinux", "selinux-state",
86ca3c9bdbSRoberto Sassu 				  state_str, strlen(state_str), false,
87ca3c9bdbSRoberto Sassu 				  NULL, 0);
882554a48fSLakshmi Ramasubramanian 
892554a48fSLakshmi Ramasubramanian 	kfree(state_str);
902554a48fSLakshmi Ramasubramanian 
91fdd1ffe8SLakshmi Ramasubramanian 	/*
92fdd1ffe8SLakshmi Ramasubramanian 	 * Measure SELinux policy only after initialization is completed.
93fdd1ffe8SLakshmi Ramasubramanian 	 */
94*e67b7985SStephen Smalley 	if (!selinux_initialized())
95fdd1ffe8SLakshmi Ramasubramanian 		return;
96fdd1ffe8SLakshmi Ramasubramanian 
97*e67b7985SStephen Smalley 	rc = security_read_state_kernel(&policy, &policy_len);
98fdd1ffe8SLakshmi Ramasubramanian 	if (rc) {
99fdd1ffe8SLakshmi Ramasubramanian 		pr_err("SELinux: %s: failed to read policy %d.\n", __func__, rc);
100fdd1ffe8SLakshmi Ramasubramanian 		return;
101fdd1ffe8SLakshmi Ramasubramanian 	}
102fdd1ffe8SLakshmi Ramasubramanian 
103fdd1ffe8SLakshmi Ramasubramanian 	ima_measure_critical_data("selinux", "selinux-policy-hash",
104ca3c9bdbSRoberto Sassu 				  policy, policy_len, true,
105ca3c9bdbSRoberto Sassu 				  NULL, 0);
106fdd1ffe8SLakshmi Ramasubramanian 
107fdd1ffe8SLakshmi Ramasubramanian 	vfree(policy);
108fdd1ffe8SLakshmi Ramasubramanian }
1092554a48fSLakshmi Ramasubramanian 
1102554a48fSLakshmi Ramasubramanian /*
1112554a48fSLakshmi Ramasubramanian  * selinux_ima_measure_state - Measure SELinux state and hash of policy
1122554a48fSLakshmi Ramasubramanian  */
selinux_ima_measure_state(void)113*e67b7985SStephen Smalley void selinux_ima_measure_state(void)
1142554a48fSLakshmi Ramasubramanian {
115*e67b7985SStephen Smalley 	lockdep_assert_not_held(&selinux_state.policy_mutex);
1162554a48fSLakshmi Ramasubramanian 
117*e67b7985SStephen Smalley 	mutex_lock(&selinux_state.policy_mutex);
118*e67b7985SStephen Smalley 	selinux_ima_measure_state_locked();
119*e67b7985SStephen Smalley 	mutex_unlock(&selinux_state.policy_mutex);
1202554a48fSLakshmi Ramasubramanian }
121