xref: /linux/security/ipe/eval.c (revision 259c4a519100e9182f264f8009ee212b32774277)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4  */
5 
6 #include <linux/fs.h>
7 #include <linux/types.h>
8 #include <linux/slab.h>
9 #include <linux/file.h>
10 #include <linux/sched.h>
11 #include <linux/rcupdate.h>
12 #include <linux/moduleparam.h>
13 #include <linux/fsverity.h>
14 
15 #include "ipe.h"
16 #include "eval.h"
17 #include "policy.h"
18 #include "audit.h"
19 #include "digest.h"
20 
21 struct ipe_policy __rcu *ipe_active_policy;
22 bool success_audit;
23 bool enforce = true;
24 #define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev)
25 
26 #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
27 
28 /**
29  * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context.
30  * @ctx: Supplies a pointer to the context to be populated.
31  * @file: Supplies the file struct of the file triggered IPE event.
32  */
33 static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file)
34 {
35 	ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
36 }
37 
38 #ifdef CONFIG_IPE_PROP_DM_VERITY
39 /**
40  * build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context.
41  * @ctx: Supplies a pointer to the context to be populated.
42  * @ino: Supplies the inode struct of the file triggered IPE event.
43  */
44 static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
45 {
46 	if (INO_BLOCK_DEV(ino))
47 		ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino));
48 }
49 #else
50 static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
51 {
52 }
53 #endif /* CONFIG_IPE_PROP_DM_VERITY */
54 
55 #ifdef CONFIG_IPE_PROP_FS_VERITY
56 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
57 static void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx,
58 				     const struct inode *const ino)
59 {
60 	ctx->ipe_inode = ipe_inode(ctx->ino);
61 }
62 #else
63 static inline void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx,
64 					    const struct inode *const ino)
65 {
66 }
67 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
68 
69 /**
70  * build_ipe_inode_ctx() - Build inode fields of an evaluation context.
71  * @ctx: Supplies a pointer to the context to be populated.
72  * @ino: Supplies the inode struct of the file triggered IPE event.
73  */
74 static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
75 {
76 	ctx->ino = ino;
77 	build_ipe_inode_blob_ctx(ctx, ino);
78 }
79 #else
80 static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
81 {
82 }
83 #endif /* CONFIG_IPE_PROP_FS_VERITY */
84 
85 /**
86  * ipe_build_eval_ctx() - Build an ipe evaluation context.
87  * @ctx: Supplies a pointer to the context to be populated.
88  * @file: Supplies a pointer to the file to associated with the evaluation.
89  * @op: Supplies the IPE policy operation associated with the evaluation.
90  * @hook: Supplies the LSM hook associated with the evaluation.
91  */
92 void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
93 			const struct file *file,
94 			enum ipe_op_type op,
95 			enum ipe_hook_type hook)
96 {
97 	struct inode *ino;
98 
99 	ctx->file = file;
100 	ctx->op = op;
101 	ctx->hook = hook;
102 
103 	if (file) {
104 		build_ipe_sb_ctx(ctx, file);
105 		ino = d_real_inode(file->f_path.dentry);
106 		build_ipe_bdev_ctx(ctx, ino);
107 		build_ipe_inode_ctx(ctx, ino);
108 	}
109 }
110 
111 /**
112  * evaluate_boot_verified() - Evaluate @ctx for the boot verified property.
113  * @ctx: Supplies a pointer to the context being evaluated.
114  *
115  * Return:
116  * * %true	- The current @ctx match the @p
117  * * %false	- The current @ctx doesn't match the @p
118  */
119 static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
120 {
121 	return ctx->initramfs;
122 }
123 
124 #ifdef CONFIG_IPE_PROP_DM_VERITY
125 /**
126  * evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property.
127  * @ctx: Supplies a pointer to the context being evaluated.
128  * @p: Supplies a pointer to the property being evaluated.
129  *
130  * Return:
131  * * %true	- The current @ctx match the @p
132  * * %false	- The current @ctx doesn't match the @p
133  */
134 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
135 				  struct ipe_prop *p)
136 {
137 	const struct digest_info *root_hash;
138 
139 	if (!ctx->ipe_bdev)
140 		return false;
141 
142 	root_hash = rcu_dereference(ctx->ipe_bdev->root_hash);
143 
144 	return root_hash && ipe_digest_eval(p->value, root_hash);
145 }
146 #else
147 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
148 				  struct ipe_prop *p)
149 {
150 	return false;
151 }
152 #endif /* CONFIG_IPE_PROP_DM_VERITY */
153 
154 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
155 /**
156  * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property.
157  * @ctx: Supplies a pointer to the context being evaluated.
158  *
159  * Return:
160  * * %true	- The current @ctx match the property
161  * * %false	- The current @ctx doesn't match the property
162  */
163 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
164 {
165 	return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed);
166 }
167 
168 /**
169  * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property.
170  * @ctx: Supplies a pointer to the context being evaluated.
171  *
172  * Return:
173  * * %true	- The current @ctx match the property
174  * * %false	- The current @ctx doesn't match the property
175  */
176 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
177 {
178 	return !evaluate_dmv_sig_false(ctx);
179 }
180 #else
181 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
182 {
183 	return false;
184 }
185 
186 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
187 {
188 	return false;
189 }
190 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
191 
192 #ifdef CONFIG_IPE_PROP_FS_VERITY
193 /**
194  * evaluate_fsv_digest() - Evaluate @ctx against a fsv digest property.
195  * @ctx: Supplies a pointer to the context being evaluated.
196  * @p: Supplies a pointer to the property being evaluated.
197  *
198  * Return:
199  * * %true	- The current @ctx match the @p
200  * * %false	- The current @ctx doesn't match the @p
201  */
202 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
203 				struct ipe_prop *p)
204 {
205 	enum hash_algo alg;
206 	u8 digest[FS_VERITY_MAX_DIGEST_SIZE];
207 	struct digest_info info;
208 
209 	if (!ctx->ino)
210 		return false;
211 	if (!fsverity_get_digest((struct inode *)ctx->ino,
212 				 digest,
213 				 NULL,
214 				 &alg))
215 		return false;
216 
217 	info.alg = hash_algo_name[alg];
218 	info.digest = digest;
219 	info.digest_len = hash_digest_size[alg];
220 
221 	return ipe_digest_eval(p->value, &info);
222 }
223 #else
224 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
225 				struct ipe_prop *p)
226 {
227 	return false;
228 }
229 #endif /* CONFIG_IPE_PROP_FS_VERITY */
230 
231 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
232 /**
233  * evaluate_fsv_sig_false() - Evaluate @ctx against a fsv sig false property.
234  * @ctx: Supplies a pointer to the context being evaluated.
235  *
236  * Return:
237  * * %true	- The current @ctx match the property
238  * * %false	- The current @ctx doesn't match the property
239  */
240 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
241 {
242 	return !ctx->ino ||
243 	       !IS_VERITY(ctx->ino) ||
244 	       !ctx->ipe_inode ||
245 	       !ctx->ipe_inode->fs_verity_signed;
246 }
247 
248 /**
249  * evaluate_fsv_sig_true() - Evaluate @ctx against a fsv sig true property.
250  * @ctx: Supplies a pointer to the context being evaluated.
251  *
252  * Return:
253  * * %true - The current @ctx match the property
254  * * %false - The current @ctx doesn't match the property
255  */
256 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
257 {
258 	return !evaluate_fsv_sig_false(ctx);
259 }
260 #else
261 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
262 {
263 	return false;
264 }
265 
266 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
267 {
268 	return false;
269 }
270 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
271 
272 /**
273  * evaluate_property() - Analyze @ctx against a rule property.
274  * @ctx: Supplies a pointer to the context to be evaluated.
275  * @p: Supplies a pointer to the property to be evaluated.
276  *
277  * This function Determines whether the specified @ctx
278  * matches the conditions defined by a rule property @p.
279  *
280  * Return:
281  * * %true	- The current @ctx match the @p
282  * * %false	- The current @ctx doesn't match the @p
283  */
284 static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
285 			      struct ipe_prop *p)
286 {
287 	switch (p->type) {
288 	case IPE_PROP_BOOT_VERIFIED_FALSE:
289 		return !evaluate_boot_verified(ctx);
290 	case IPE_PROP_BOOT_VERIFIED_TRUE:
291 		return evaluate_boot_verified(ctx);
292 	case IPE_PROP_DMV_ROOTHASH:
293 		return evaluate_dmv_roothash(ctx, p);
294 	case IPE_PROP_DMV_SIG_FALSE:
295 		return evaluate_dmv_sig_false(ctx);
296 	case IPE_PROP_DMV_SIG_TRUE:
297 		return evaluate_dmv_sig_true(ctx);
298 	case IPE_PROP_FSV_DIGEST:
299 		return evaluate_fsv_digest(ctx, p);
300 	case IPE_PROP_FSV_SIG_FALSE:
301 		return evaluate_fsv_sig_false(ctx);
302 	case IPE_PROP_FSV_SIG_TRUE:
303 		return evaluate_fsv_sig_true(ctx);
304 	default:
305 		return false;
306 	}
307 }
308 
309 /**
310  * ipe_evaluate_event() - Analyze @ctx against the current active policy.
311  * @ctx: Supplies a pointer to the context to be evaluated.
312  *
313  * This is the loop where all policy evaluations happen against the IPE policy.
314  *
315  * Return:
316  * * %0		- Success
317  * * %-EACCES	- @ctx did not pass evaluation
318  */
319 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
320 {
321 	const struct ipe_op_table *rules = NULL;
322 	const struct ipe_rule *rule = NULL;
323 	struct ipe_policy *pol = NULL;
324 	struct ipe_prop *prop = NULL;
325 	enum ipe_action_type action;
326 	enum ipe_match match_type;
327 	bool match = false;
328 	int rc = 0;
329 
330 	rcu_read_lock();
331 
332 	pol = rcu_dereference(ipe_active_policy);
333 	if (!pol) {
334 		rcu_read_unlock();
335 		return 0;
336 	}
337 
338 	if (ctx->op == IPE_OP_INVALID) {
339 		if (pol->parsed->global_default_action == IPE_ACTION_INVALID) {
340 			WARN(1, "no default rule set for unknown op, ALLOW it");
341 			action = IPE_ACTION_ALLOW;
342 		} else {
343 			action = pol->parsed->global_default_action;
344 		}
345 		match_type = IPE_MATCH_GLOBAL;
346 		goto eval;
347 	}
348 
349 	rules = &pol->parsed->rules[ctx->op];
350 
351 	list_for_each_entry(rule, &rules->rules, next) {
352 		match = true;
353 
354 		list_for_each_entry(prop, &rule->props, next) {
355 			match = evaluate_property(ctx, prop);
356 			if (!match)
357 				break;
358 		}
359 
360 		if (match)
361 			break;
362 	}
363 
364 	if (match) {
365 		action = rule->action;
366 		match_type = IPE_MATCH_RULE;
367 	} else if (rules->default_action != IPE_ACTION_INVALID) {
368 		action = rules->default_action;
369 		match_type = IPE_MATCH_TABLE;
370 	} else {
371 		action = pol->parsed->global_default_action;
372 		match_type = IPE_MATCH_GLOBAL;
373 	}
374 
375 eval:
376 	ipe_audit_match(ctx, match_type, action, rule);
377 	rcu_read_unlock();
378 
379 	if (action == IPE_ACTION_DENY)
380 		rc = -EACCES;
381 
382 	if (!READ_ONCE(enforce))
383 		rc = 0;
384 
385 	return rc;
386 }
387 
388 /* Set the right module name */
389 #ifdef KBUILD_MODNAME
390 #undef KBUILD_MODNAME
391 #define KBUILD_MODNAME "ipe"
392 #endif
393 
394 module_param(success_audit, bool, 0400);
395 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
396 module_param(enforce, bool, 0400);
397 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
398