Commit | Line | Data |
---|---|---|
fdd1ffe8 LR |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2021 Microsoft Corporation | |
4 | * | |
5 | * Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com) | |
6 | * | |
3d9047a0 | 7 | * Measure critical data structures maintained by SELinux |
fdd1ffe8 LR |
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 | /* | |
2554a48f | 16 | * selinux_ima_collect_state - Read selinux configuration settings |
fdd1ffe8 | 17 | * |
2554a48f LR |
18 | * On success returns the configuration settings string. |
19 | * On error, returns NULL. | |
fdd1ffe8 | 20 | */ |
e67b7985 | 21 | static char *selinux_ima_collect_state(void) |
fdd1ffe8 | 22 | { |
2554a48f LR |
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); | |
cdbec3ed | 30 | for (i = 0; i < __POLICYDB_CAP_MAX; i++) |
2554a48f LR |
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 | ||
e67b7985 | 40 | rc = strlcat(buf, selinux_initialized() ? on : off, buf_len); |
2554a48f LR |
41 | WARN_ON(rc >= buf_len); |
42 | ||
43 | rc = strlcat(buf, "enforcing", buf_len); | |
44 | WARN_ON(rc >= buf_len); | |
45 | ||
e67b7985 | 46 | rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len); |
2554a48f LR |
47 | WARN_ON(rc >= buf_len); |
48 | ||
49 | rc = strlcat(buf, "checkreqprot", buf_len); | |
50 | WARN_ON(rc >= buf_len); | |
51 | ||
e67b7985 | 52 | rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len); |
2554a48f LR |
53 | WARN_ON(rc >= buf_len); |
54 | ||
cdbec3ed | 55 | for (i = 0; i < __POLICYDB_CAP_MAX; i++) { |
2554a48f LR |
56 | rc = strlcat(buf, selinux_policycap_names[i], buf_len); |
57 | WARN_ON(rc >= buf_len); | |
58 | ||
e67b7985 SS |
59 | rc = strlcat(buf, selinux_state.policycap[i] ? on : off, |
60 | buf_len); | |
2554a48f LR |
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 | |
2554a48f | 69 | */ |
e67b7985 | 70 | void selinux_ima_measure_state_locked(void) |
2554a48f LR |
71 | { |
72 | char *state_str = NULL; | |
fdd1ffe8 LR |
73 | void *policy = NULL; |
74 | size_t policy_len; | |
75 | int rc = 0; | |
76 | ||
e67b7985 | 77 | lockdep_assert_held(&selinux_state.policy_mutex); |
2554a48f | 78 | |
e67b7985 | 79 | state_str = selinux_ima_collect_state(); |
2554a48f LR |
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", | |
ca3c9bdb RS |
86 | state_str, strlen(state_str), false, |
87 | NULL, 0); | |
2554a48f LR |
88 | |
89 | kfree(state_str); | |
90 | ||
fdd1ffe8 LR |
91 | /* |
92 | * Measure SELinux policy only after initialization is completed. | |
93 | */ | |
e67b7985 | 94 | if (!selinux_initialized()) |
fdd1ffe8 LR |
95 | return; |
96 | ||
e67b7985 | 97 | rc = security_read_state_kernel(&policy, &policy_len); |
fdd1ffe8 LR |
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", | |
ca3c9bdb RS |
104 | policy, policy_len, true, |
105 | NULL, 0); | |
fdd1ffe8 LR |
106 | |
107 | vfree(policy); | |
108 | } | |
2554a48f LR |
109 | |
110 | /* | |
111 | * selinux_ima_measure_state - Measure SELinux state and hash of policy | |
2554a48f | 112 | */ |
e67b7985 | 113 | void selinux_ima_measure_state(void) |
2554a48f | 114 | { |
e67b7985 | 115 | lockdep_assert_not_held(&selinux_state.policy_mutex); |
2554a48f | 116 | |
e67b7985 SS |
117 | mutex_lock(&selinux_state.policy_mutex); |
118 | selinux_ima_measure_state_locked(); | |
119 | mutex_unlock(&selinux_state.policy_mutex); | |
2554a48f | 120 | } |