xref: /linux/security/ipe/eval.c (revision a430d95c5efa2b545d26a094eb5f624e36732af0)
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  */
build_ipe_sb_ctx(struct ipe_eval_ctx * ctx,const struct file * const file)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  */
build_ipe_bdev_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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
build_ipe_bdev_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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
build_ipe_inode_blob_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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
build_ipe_inode_blob_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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  */
build_ipe_inode_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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
build_ipe_inode_ctx(struct ipe_eval_ctx * ctx,const struct inode * const ino)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  */
ipe_build_eval_ctx(struct ipe_eval_ctx * ctx,const struct file * file,enum ipe_op_type op,enum ipe_hook_type hook)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  */
evaluate_boot_verified(const struct ipe_eval_ctx * const ctx)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  */
evaluate_dmv_roothash(const struct ipe_eval_ctx * const ctx,struct ipe_prop * p)134 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
135 				  struct ipe_prop *p)
136 {
137 	return !!ctx->ipe_bdev &&
138 	       !!ctx->ipe_bdev->root_hash &&
139 	       ipe_digest_eval(p->value,
140 			       ctx->ipe_bdev->root_hash);
141 }
142 #else
evaluate_dmv_roothash(const struct ipe_eval_ctx * const ctx,struct ipe_prop * p)143 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
144 				  struct ipe_prop *p)
145 {
146 	return false;
147 }
148 #endif /* CONFIG_IPE_PROP_DM_VERITY */
149 
150 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
151 /**
152  * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property.
153  * @ctx: Supplies a pointer to the context being evaluated.
154  *
155  * Return:
156  * * %true	- The current @ctx match the property
157  * * %false	- The current @ctx doesn't match the property
158  */
evaluate_dmv_sig_false(const struct ipe_eval_ctx * const ctx)159 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
160 {
161 	return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed);
162 }
163 
164 /**
165  * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property.
166  * @ctx: Supplies a pointer to the context being evaluated.
167  *
168  * Return:
169  * * %true	- The current @ctx match the property
170  * * %false	- The current @ctx doesn't match the property
171  */
evaluate_dmv_sig_true(const struct ipe_eval_ctx * const ctx)172 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
173 {
174 	return !evaluate_dmv_sig_false(ctx);
175 }
176 #else
evaluate_dmv_sig_false(const struct ipe_eval_ctx * const ctx)177 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
178 {
179 	return false;
180 }
181 
evaluate_dmv_sig_true(const struct ipe_eval_ctx * const ctx)182 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
183 {
184 	return false;
185 }
186 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
187 
188 #ifdef CONFIG_IPE_PROP_FS_VERITY
189 /**
190  * evaluate_fsv_digest() - Evaluate @ctx against a fsv digest property.
191  * @ctx: Supplies a pointer to the context being evaluated.
192  * @p: Supplies a pointer to the property being evaluated.
193  *
194  * Return:
195  * * %true	- The current @ctx match the @p
196  * * %false	- The current @ctx doesn't match the @p
197  */
evaluate_fsv_digest(const struct ipe_eval_ctx * const ctx,struct ipe_prop * p)198 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
199 				struct ipe_prop *p)
200 {
201 	enum hash_algo alg;
202 	u8 digest[FS_VERITY_MAX_DIGEST_SIZE];
203 	struct digest_info info;
204 
205 	if (!ctx->ino)
206 		return false;
207 	if (!fsverity_get_digest((struct inode *)ctx->ino,
208 				 digest,
209 				 NULL,
210 				 &alg))
211 		return false;
212 
213 	info.alg = hash_algo_name[alg];
214 	info.digest = digest;
215 	info.digest_len = hash_digest_size[alg];
216 
217 	return ipe_digest_eval(p->value, &info);
218 }
219 #else
evaluate_fsv_digest(const struct ipe_eval_ctx * const ctx,struct ipe_prop * p)220 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx,
221 				struct ipe_prop *p)
222 {
223 	return false;
224 }
225 #endif /* CONFIG_IPE_PROP_FS_VERITY */
226 
227 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
228 /**
229  * evaluate_fsv_sig_false() - Evaluate @ctx against a fsv sig false property.
230  * @ctx: Supplies a pointer to the context being evaluated.
231  *
232  * Return:
233  * * %true	- The current @ctx match the property
234  * * %false	- The current @ctx doesn't match the property
235  */
evaluate_fsv_sig_false(const struct ipe_eval_ctx * const ctx)236 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
237 {
238 	return !ctx->ino ||
239 	       !IS_VERITY(ctx->ino) ||
240 	       !ctx->ipe_inode ||
241 	       !ctx->ipe_inode->fs_verity_signed;
242 }
243 
244 /**
245  * evaluate_fsv_sig_true() - Evaluate @ctx against a fsv sig true property.
246  * @ctx: Supplies a pointer to the context being evaluated.
247  *
248  * Return:
249  * * %true - The current @ctx match the property
250  * * %false - The current @ctx doesn't match the property
251  */
evaluate_fsv_sig_true(const struct ipe_eval_ctx * const ctx)252 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
253 {
254 	return !evaluate_fsv_sig_false(ctx);
255 }
256 #else
evaluate_fsv_sig_false(const struct ipe_eval_ctx * const ctx)257 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
258 {
259 	return false;
260 }
261 
evaluate_fsv_sig_true(const struct ipe_eval_ctx * const ctx)262 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
263 {
264 	return false;
265 }
266 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
267 
268 /**
269  * evaluate_property() - Analyze @ctx against a rule property.
270  * @ctx: Supplies a pointer to the context to be evaluated.
271  * @p: Supplies a pointer to the property to be evaluated.
272  *
273  * This function Determines whether the specified @ctx
274  * matches the conditions defined by a rule property @p.
275  *
276  * Return:
277  * * %true	- The current @ctx match the @p
278  * * %false	- The current @ctx doesn't match the @p
279  */
evaluate_property(const struct ipe_eval_ctx * const ctx,struct ipe_prop * p)280 static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
281 			      struct ipe_prop *p)
282 {
283 	switch (p->type) {
284 	case IPE_PROP_BOOT_VERIFIED_FALSE:
285 		return !evaluate_boot_verified(ctx);
286 	case IPE_PROP_BOOT_VERIFIED_TRUE:
287 		return evaluate_boot_verified(ctx);
288 	case IPE_PROP_DMV_ROOTHASH:
289 		return evaluate_dmv_roothash(ctx, p);
290 	case IPE_PROP_DMV_SIG_FALSE:
291 		return evaluate_dmv_sig_false(ctx);
292 	case IPE_PROP_DMV_SIG_TRUE:
293 		return evaluate_dmv_sig_true(ctx);
294 	case IPE_PROP_FSV_DIGEST:
295 		return evaluate_fsv_digest(ctx, p);
296 	case IPE_PROP_FSV_SIG_FALSE:
297 		return evaluate_fsv_sig_false(ctx);
298 	case IPE_PROP_FSV_SIG_TRUE:
299 		return evaluate_fsv_sig_true(ctx);
300 	default:
301 		return false;
302 	}
303 }
304 
305 /**
306  * ipe_evaluate_event() - Analyze @ctx against the current active policy.
307  * @ctx: Supplies a pointer to the context to be evaluated.
308  *
309  * This is the loop where all policy evaluations happen against the IPE policy.
310  *
311  * Return:
312  * * %0		- Success
313  * * %-EACCES	- @ctx did not pass evaluation
314  */
ipe_evaluate_event(const struct ipe_eval_ctx * const ctx)315 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
316 {
317 	const struct ipe_op_table *rules = NULL;
318 	const struct ipe_rule *rule = NULL;
319 	struct ipe_policy *pol = NULL;
320 	struct ipe_prop *prop = NULL;
321 	enum ipe_action_type action;
322 	enum ipe_match match_type;
323 	bool match = false;
324 	int rc = 0;
325 
326 	rcu_read_lock();
327 
328 	pol = rcu_dereference(ipe_active_policy);
329 	if (!pol) {
330 		rcu_read_unlock();
331 		return 0;
332 	}
333 
334 	if (ctx->op == IPE_OP_INVALID) {
335 		if (pol->parsed->global_default_action == IPE_ACTION_INVALID) {
336 			WARN(1, "no default rule set for unknown op, ALLOW it");
337 			action = IPE_ACTION_ALLOW;
338 		} else {
339 			action = pol->parsed->global_default_action;
340 		}
341 		match_type = IPE_MATCH_GLOBAL;
342 		goto eval;
343 	}
344 
345 	rules = &pol->parsed->rules[ctx->op];
346 
347 	list_for_each_entry(rule, &rules->rules, next) {
348 		match = true;
349 
350 		list_for_each_entry(prop, &rule->props, next) {
351 			match = evaluate_property(ctx, prop);
352 			if (!match)
353 				break;
354 		}
355 
356 		if (match)
357 			break;
358 	}
359 
360 	if (match) {
361 		action = rule->action;
362 		match_type = IPE_MATCH_RULE;
363 	} else if (rules->default_action != IPE_ACTION_INVALID) {
364 		action = rules->default_action;
365 		match_type = IPE_MATCH_TABLE;
366 	} else {
367 		action = pol->parsed->global_default_action;
368 		match_type = IPE_MATCH_GLOBAL;
369 	}
370 
371 eval:
372 	ipe_audit_match(ctx, match_type, action, rule);
373 	rcu_read_unlock();
374 
375 	if (action == IPE_ACTION_DENY)
376 		rc = -EACCES;
377 
378 	if (!READ_ONCE(enforce))
379 		rc = 0;
380 
381 	return rc;
382 }
383 
384 /* Set the right module name */
385 #ifdef KBUILD_MODNAME
386 #undef KBUILD_MODNAME
387 #define KBUILD_MODNAME "ipe"
388 #endif
389 
390 module_param(success_audit, bool, 0400);
391 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
392 module_param(enforce, bool, 0400);
393 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
394