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