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