1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4 */
5
6 #include <linux/slab.h>
7 #include <linux/audit.h>
8 #include <linux/types.h>
9 #include <crypto/sha2.h>
10
11 #include "ipe.h"
12 #include "eval.h"
13 #include "hooks.h"
14 #include "policy.h"
15 #include "audit.h"
16 #include "digest.h"
17
18 #define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY")
19
20 #define IPE_AUDIT_HASH_ALG "sha256" /* keep in sync with audit_policy() */
21
22 #define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\
23 "policy_digest=" IPE_AUDIT_HASH_ALG ":"
24 #define AUDIT_POLICY_LOAD_NULL_FMT "policy_name=? policy_version=? "\
25 "policy_digest=?"
26 #define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\
27 "old_active_pol_version=%hu.%hu.%hu "\
28 "old_policy_digest=" IPE_AUDIT_HASH_ALG ":"
29 #define AUDIT_OLD_ACTIVE_POLICY_NULL_FMT "old_active_pol_name=? "\
30 "old_active_pol_version=? "\
31 "old_policy_digest=?"
32 #define AUDIT_NEW_ACTIVE_POLICY_FMT "new_active_pol_name=\"%s\" "\
33 "new_active_pol_version=%hu.%hu.%hu "\
34 "new_policy_digest=" IPE_AUDIT_HASH_ALG ":"
35
36 static const char *const audit_op_names[__IPE_OP_MAX + 1] = {
37 "EXECUTE",
38 "FIRMWARE",
39 "KMODULE",
40 "KEXEC_IMAGE",
41 "KEXEC_INITRAMFS",
42 "POLICY",
43 "X509_CERT",
44 "UNKNOWN",
45 };
46
47 static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
48 "BPRM_CHECK",
49 "BPRM_CREDS_FOR_EXEC",
50 "MMAP",
51 "MPROTECT",
52 "KERNEL_READ",
53 "KERNEL_LOAD",
54 };
55
56 static const char *const audit_prop_names[__IPE_PROP_MAX] = {
57 "boot_verified=FALSE",
58 "boot_verified=TRUE",
59 "dmverity_roothash=",
60 "dmverity_signature=FALSE",
61 "dmverity_signature=TRUE",
62 "fsverity_digest=",
63 "fsverity_signature=FALSE",
64 "fsverity_signature=TRUE",
65 };
66
67 /**
68 * audit_dmv_roothash() - audit the roothash of a dmverity_roothash property.
69 * @ab: Supplies a pointer to the audit_buffer to append to.
70 * @rh: Supplies a pointer to the digest structure.
71 */
audit_dmv_roothash(struct audit_buffer * ab,const void * rh)72 static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh)
73 {
74 audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_DMV_ROOTHASH]);
75 ipe_digest_audit(ab, rh);
76 }
77
78 /**
79 * audit_fsv_digest() - audit the digest of a fsverity_digest property.
80 * @ab: Supplies a pointer to the audit_buffer to append to.
81 * @d: Supplies a pointer to the digest structure.
82 */
audit_fsv_digest(struct audit_buffer * ab,const void * d)83 static void audit_fsv_digest(struct audit_buffer *ab, const void *d)
84 {
85 audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]);
86 ipe_digest_audit(ab, d);
87 }
88
89 /**
90 * audit_rule() - audit an IPE policy rule.
91 * @ab: Supplies a pointer to the audit_buffer to append to.
92 * @r: Supplies a pointer to the ipe_rule to approximate a string form for.
93 */
audit_rule(struct audit_buffer * ab,const struct ipe_rule * r)94 static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
95 {
96 const struct ipe_prop *ptr;
97
98 audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]);
99
100 list_for_each_entry(ptr, &r->props, next) {
101 switch (ptr->type) {
102 case IPE_PROP_DMV_ROOTHASH:
103 audit_dmv_roothash(ab, ptr->value);
104 break;
105 case IPE_PROP_FSV_DIGEST:
106 audit_fsv_digest(ab, ptr->value);
107 break;
108 default:
109 audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
110 break;
111 }
112
113 audit_log_format(ab, " ");
114 }
115
116 audit_log_format(ab, "action=%s\"", ACTSTR(r->action));
117 }
118
119 /**
120 * ipe_audit_match() - Audit a rule match in a policy evaluation.
121 * @ctx: Supplies a pointer to the evaluation context that was used in the
122 * evaluation.
123 * @match_type: Supplies the scope of the match: rule, operation default,
124 * global default.
125 * @act: Supplies the IPE's evaluation decision, deny or allow.
126 * @r: Supplies a pointer to the rule that was matched, if possible.
127 */
ipe_audit_match(const struct ipe_eval_ctx * const ctx,enum ipe_match match_type,enum ipe_action_type act,const struct ipe_rule * const r)128 void ipe_audit_match(const struct ipe_eval_ctx *const ctx,
129 enum ipe_match match_type,
130 enum ipe_action_type act, const struct ipe_rule *const r)
131 {
132 const char *op = audit_op_names[ctx->op];
133 char comm[sizeof(current->comm)];
134 struct audit_buffer *ab;
135 struct inode *inode;
136
137 if (act != IPE_ACTION_DENY && !READ_ONCE(success_audit))
138 return;
139
140 ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
141 AUDIT_IPE_ACCESS);
142 if (!ab)
143 return;
144
145 audit_log_format(ab, "ipe_op=%s ipe_hook=%s enforcing=%d pid=%d comm=",
146 op, audit_hook_names[ctx->hook], READ_ONCE(enforce),
147 task_tgid_nr(current));
148 audit_log_untrustedstring(ab, get_task_comm(comm, current));
149
150 if (ctx->file) {
151 audit_log_d_path(ab, " path=", &ctx->file->f_path);
152 inode = file_inode(ctx->file);
153 if (inode) {
154 audit_log_format(ab, " dev=");
155 audit_log_untrustedstring(ab, inode->i_sb->s_id);
156 audit_log_format(ab, " ino=%lu", inode->i_ino);
157 } else {
158 audit_log_format(ab, " dev=? ino=?");
159 }
160 } else {
161 audit_log_format(ab, " path=? dev=? ino=?");
162 }
163
164 if (match_type == IPE_MATCH_RULE)
165 audit_rule(ab, r);
166 else if (match_type == IPE_MATCH_TABLE)
167 audit_log_format(ab, " rule=\"DEFAULT op=%s action=%s\"", op,
168 ACTSTR(act));
169 else
170 audit_log_format(ab, " rule=\"DEFAULT action=%s\"",
171 ACTSTR(act));
172
173 audit_log_end(ab);
174 }
175
176 /**
177 * audit_policy() - Audit a policy's name, version and thumbprint to @ab.
178 * @ab: Supplies a pointer to the audit buffer to append to.
179 * @audit_format: Supplies a pointer to the audit format string
180 * @p: Supplies a pointer to the policy to audit.
181 */
audit_policy(struct audit_buffer * ab,const char * audit_format,const struct ipe_policy * const p)182 static void audit_policy(struct audit_buffer *ab,
183 const char *audit_format,
184 const struct ipe_policy *const p)
185 {
186 u8 digest[SHA256_DIGEST_SIZE];
187
188 sha256(p->pkcs7, p->pkcs7len, digest);
189
190 audit_log_format(ab, audit_format, p->parsed->name,
191 p->parsed->version.major, p->parsed->version.minor,
192 p->parsed->version.rev);
193 audit_log_n_hex(ab, digest, sizeof(digest));
194 }
195
196 /**
197 * ipe_audit_policy_activation() - Audit a policy being activated.
198 * @op: Supplies a pointer to the previously activated policy to audit.
199 * @np: Supplies a pointer to the newly activated policy to audit.
200 */
ipe_audit_policy_activation(const struct ipe_policy * const op,const struct ipe_policy * const np)201 void ipe_audit_policy_activation(const struct ipe_policy *const op,
202 const struct ipe_policy *const np)
203 {
204 struct audit_buffer *ab;
205
206 ab = audit_log_start(audit_context(), GFP_KERNEL,
207 AUDIT_IPE_CONFIG_CHANGE);
208 if (!ab)
209 return;
210
211 if (op) {
212 audit_policy(ab, AUDIT_OLD_ACTIVE_POLICY_FMT, op);
213 audit_log_format(ab, " ");
214 } else {
215 /*
216 * old active policy can be NULL if there is no kernel
217 * built-in policy
218 */
219 audit_log_format(ab, AUDIT_OLD_ACTIVE_POLICY_NULL_FMT);
220 audit_log_format(ab, " ");
221 }
222 audit_policy(ab, AUDIT_NEW_ACTIVE_POLICY_FMT, np);
223 audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1",
224 from_kuid(&init_user_ns, audit_get_loginuid(current)),
225 audit_get_sessionid(current));
226
227 audit_log_end(ab);
228 }
229
230 /**
231 * ipe_audit_policy_load() - Audit a policy loading event.
232 * @p: Supplies a pointer to the policy to audit or an error pointer.
233 */
ipe_audit_policy_load(const struct ipe_policy * const p)234 void ipe_audit_policy_load(const struct ipe_policy *const p)
235 {
236 struct audit_buffer *ab;
237 int err = 0;
238
239 ab = audit_log_start(audit_context(), GFP_KERNEL,
240 AUDIT_IPE_POLICY_LOAD);
241 if (!ab)
242 return;
243
244 if (!IS_ERR(p)) {
245 audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
246 } else {
247 audit_log_format(ab, AUDIT_POLICY_LOAD_NULL_FMT);
248 err = PTR_ERR(p);
249 }
250
251 audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=%d errno=%d",
252 from_kuid(&init_user_ns, audit_get_loginuid(current)),
253 audit_get_sessionid(current), !err, err);
254
255 audit_log_end(ab);
256 }
257
258 /**
259 * ipe_audit_enforce() - Audit a change in IPE's enforcement state.
260 * @new_enforce: The new value enforce to be set.
261 * @old_enforce: The old value currently in enforce.
262 */
ipe_audit_enforce(bool new_enforce,bool old_enforce)263 void ipe_audit_enforce(bool new_enforce, bool old_enforce)
264 {
265 struct audit_buffer *ab;
266
267 ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS);
268 if (!ab)
269 return;
270
271 audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
272 "enforcing=%d old_enforcing=%d auid=%u ses=%u"
273 " enabled=1 old-enabled=1 lsm=ipe res=1",
274 new_enforce, old_enforce,
275 from_kuid(&init_user_ns, audit_get_loginuid(current)),
276 audit_get_sessionid(current));
277
278 audit_log_end(ab);
279 }
280