xref: /linux/security/ipe/eval.c (revision e155858dd99523d4afe0f74e9c26e4f4499eb5af)
105a35163SDeven Bowers // SPDX-License-Identifier: GPL-2.0
205a35163SDeven Bowers /*
305a35163SDeven Bowers  * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
405a35163SDeven Bowers  */
505a35163SDeven Bowers 
605a35163SDeven Bowers #include <linux/fs.h>
705a35163SDeven Bowers #include <linux/types.h>
805a35163SDeven Bowers #include <linux/slab.h>
905a35163SDeven Bowers #include <linux/file.h>
1005a35163SDeven Bowers #include <linux/sched.h>
1105a35163SDeven Bowers #include <linux/rcupdate.h>
12f44554b5SDeven Bowers #include <linux/moduleparam.h>
1305a35163SDeven Bowers 
1405a35163SDeven Bowers #include "ipe.h"
1505a35163SDeven Bowers #include "eval.h"
1605a35163SDeven Bowers #include "policy.h"
17f44554b5SDeven Bowers #include "audit.h"
18*e155858dSDeven Bowers #include "digest.h"
1905a35163SDeven Bowers 
2005a35163SDeven Bowers struct ipe_policy __rcu *ipe_active_policy;
21f44554b5SDeven Bowers bool success_audit;
22a68916eaSDeven Bowers bool enforce = true;
23*e155858dSDeven Bowers #define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev)
2405a35163SDeven Bowers 
25a8a74df1SFan Wu #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
26a8a74df1SFan Wu 
27a8a74df1SFan Wu /**
28a8a74df1SFan Wu  * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context.
29a8a74df1SFan Wu  * @ctx: Supplies a pointer to the context to be populated.
30a8a74df1SFan Wu  * @file: Supplies the file struct of the file triggered IPE event.
31a8a74df1SFan Wu  */
32a8a74df1SFan Wu static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file)
33a8a74df1SFan Wu {
34a8a74df1SFan Wu 	ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
35a8a74df1SFan Wu }
36a8a74df1SFan Wu 
37*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY
38*e155858dSDeven Bowers /**
39*e155858dSDeven Bowers  * build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context.
40*e155858dSDeven Bowers  * @ctx: Supplies a pointer to the context to be populated.
41*e155858dSDeven Bowers  * @ino: Supplies the inode struct of the file triggered IPE event.
42*e155858dSDeven Bowers  */
43*e155858dSDeven Bowers static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
44*e155858dSDeven Bowers {
45*e155858dSDeven Bowers 	if (INO_BLOCK_DEV(ino))
46*e155858dSDeven Bowers 		ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino));
47*e155858dSDeven Bowers }
48*e155858dSDeven Bowers #else
49*e155858dSDeven Bowers static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
50*e155858dSDeven Bowers {
51*e155858dSDeven Bowers }
52*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY */
53*e155858dSDeven Bowers 
5405a35163SDeven Bowers /**
5552443cb6SDeven Bowers  * ipe_build_eval_ctx() - Build an ipe evaluation context.
5652443cb6SDeven Bowers  * @ctx: Supplies a pointer to the context to be populated.
5752443cb6SDeven Bowers  * @file: Supplies a pointer to the file to associated with the evaluation.
5852443cb6SDeven Bowers  * @op: Supplies the IPE policy operation associated with the evaluation.
59f44554b5SDeven Bowers  * @hook: Supplies the LSM hook associated with the evaluation.
6052443cb6SDeven Bowers  */
6152443cb6SDeven Bowers void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
6252443cb6SDeven Bowers 			const struct file *file,
63f44554b5SDeven Bowers 			enum ipe_op_type op,
64f44554b5SDeven Bowers 			enum ipe_hook_type hook)
6552443cb6SDeven Bowers {
6652443cb6SDeven Bowers 	ctx->file = file;
6752443cb6SDeven Bowers 	ctx->op = op;
68f44554b5SDeven Bowers 	ctx->hook = hook;
69a8a74df1SFan Wu 
70*e155858dSDeven Bowers 	if (file) {
71a8a74df1SFan Wu 		build_ipe_sb_ctx(ctx, file);
72*e155858dSDeven Bowers 		build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry));
73*e155858dSDeven Bowers 	}
74a8a74df1SFan Wu }
75a8a74df1SFan Wu 
76a8a74df1SFan Wu /**
77a8a74df1SFan Wu  * evaluate_boot_verified() - Evaluate @ctx for the boot verified property.
78a8a74df1SFan Wu  * @ctx: Supplies a pointer to the context being evaluated.
79a8a74df1SFan Wu  *
80a8a74df1SFan Wu  * Return:
81a8a74df1SFan Wu  * * %true	- The current @ctx match the @p
82a8a74df1SFan Wu  * * %false	- The current @ctx doesn't match the @p
83a8a74df1SFan Wu  */
84a8a74df1SFan Wu static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
85a8a74df1SFan Wu {
86a8a74df1SFan Wu 	return ctx->initramfs;
8752443cb6SDeven Bowers }
8852443cb6SDeven Bowers 
89*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY
90*e155858dSDeven Bowers /**
91*e155858dSDeven Bowers  * evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property.
92*e155858dSDeven Bowers  * @ctx: Supplies a pointer to the context being evaluated.
93*e155858dSDeven Bowers  * @p: Supplies a pointer to the property being evaluated.
94*e155858dSDeven Bowers  *
95*e155858dSDeven Bowers  * Return:
96*e155858dSDeven Bowers  * * %true	- The current @ctx match the @p
97*e155858dSDeven Bowers  * * %false	- The current @ctx doesn't match the @p
98*e155858dSDeven Bowers  */
99*e155858dSDeven Bowers static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
100*e155858dSDeven Bowers 				  struct ipe_prop *p)
101*e155858dSDeven Bowers {
102*e155858dSDeven Bowers 	return !!ctx->ipe_bdev &&
103*e155858dSDeven Bowers 	       !!ctx->ipe_bdev->root_hash &&
104*e155858dSDeven Bowers 	       ipe_digest_eval(p->value,
105*e155858dSDeven Bowers 			       ctx->ipe_bdev->root_hash);
106*e155858dSDeven Bowers }
107*e155858dSDeven Bowers #else
108*e155858dSDeven Bowers static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
109*e155858dSDeven Bowers 				  struct ipe_prop *p)
110*e155858dSDeven Bowers {
111*e155858dSDeven Bowers 	return false;
112*e155858dSDeven Bowers }
113*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY */
114*e155858dSDeven Bowers 
115*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
116*e155858dSDeven Bowers /**
117*e155858dSDeven Bowers  * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property.
118*e155858dSDeven Bowers  * @ctx: Supplies a pointer to the context being evaluated.
119*e155858dSDeven Bowers  *
120*e155858dSDeven Bowers  * Return:
121*e155858dSDeven Bowers  * * %true	- The current @ctx match the property
122*e155858dSDeven Bowers  * * %false	- The current @ctx doesn't match the property
123*e155858dSDeven Bowers  */
124*e155858dSDeven Bowers static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
125*e155858dSDeven Bowers {
126*e155858dSDeven Bowers 	return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed);
127*e155858dSDeven Bowers }
128*e155858dSDeven Bowers 
129*e155858dSDeven Bowers /**
130*e155858dSDeven Bowers  * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property.
131*e155858dSDeven Bowers  * @ctx: Supplies a pointer to the context being evaluated.
132*e155858dSDeven Bowers  *
133*e155858dSDeven Bowers  * Return:
134*e155858dSDeven Bowers  * * %true	- The current @ctx match the property
135*e155858dSDeven Bowers  * * %false	- The current @ctx doesn't match the property
136*e155858dSDeven Bowers  */
137*e155858dSDeven Bowers static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
138*e155858dSDeven Bowers {
139*e155858dSDeven Bowers 	return !evaluate_dmv_sig_false(ctx);
140*e155858dSDeven Bowers }
141*e155858dSDeven Bowers #else
142*e155858dSDeven Bowers static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
143*e155858dSDeven Bowers {
144*e155858dSDeven Bowers 	return false;
145*e155858dSDeven Bowers }
146*e155858dSDeven Bowers 
147*e155858dSDeven Bowers static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
148*e155858dSDeven Bowers {
149*e155858dSDeven Bowers 	return false;
150*e155858dSDeven Bowers }
151*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
152*e155858dSDeven Bowers 
15352443cb6SDeven Bowers /**
15405a35163SDeven Bowers  * evaluate_property() - Analyze @ctx against a rule property.
15505a35163SDeven Bowers  * @ctx: Supplies a pointer to the context to be evaluated.
15605a35163SDeven Bowers  * @p: Supplies a pointer to the property to be evaluated.
15705a35163SDeven Bowers  *
158a8a74df1SFan Wu  * This function Determines whether the specified @ctx
159a8a74df1SFan Wu  * matches the conditions defined by a rule property @p.
16005a35163SDeven Bowers  *
16105a35163SDeven Bowers  * Return:
16205a35163SDeven Bowers  * * %true	- The current @ctx match the @p
16305a35163SDeven Bowers  * * %false	- The current @ctx doesn't match the @p
16405a35163SDeven Bowers  */
16505a35163SDeven Bowers static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
16605a35163SDeven Bowers 			      struct ipe_prop *p)
16705a35163SDeven Bowers {
168a8a74df1SFan Wu 	switch (p->type) {
169a8a74df1SFan Wu 	case IPE_PROP_BOOT_VERIFIED_FALSE:
170a8a74df1SFan Wu 		return !evaluate_boot_verified(ctx);
171a8a74df1SFan Wu 	case IPE_PROP_BOOT_VERIFIED_TRUE:
172a8a74df1SFan Wu 		return evaluate_boot_verified(ctx);
173*e155858dSDeven Bowers 	case IPE_PROP_DMV_ROOTHASH:
174*e155858dSDeven Bowers 		return evaluate_dmv_roothash(ctx, p);
175*e155858dSDeven Bowers 	case IPE_PROP_DMV_SIG_FALSE:
176*e155858dSDeven Bowers 		return evaluate_dmv_sig_false(ctx);
177*e155858dSDeven Bowers 	case IPE_PROP_DMV_SIG_TRUE:
178*e155858dSDeven Bowers 		return evaluate_dmv_sig_true(ctx);
179a8a74df1SFan Wu 	default:
18005a35163SDeven Bowers 		return false;
18105a35163SDeven Bowers 	}
182a8a74df1SFan Wu }
18305a35163SDeven Bowers 
18405a35163SDeven Bowers /**
18505a35163SDeven Bowers  * ipe_evaluate_event() - Analyze @ctx against the current active policy.
18605a35163SDeven Bowers  * @ctx: Supplies a pointer to the context to be evaluated.
18705a35163SDeven Bowers  *
18805a35163SDeven Bowers  * This is the loop where all policy evaluations happen against the IPE policy.
18905a35163SDeven Bowers  *
19005a35163SDeven Bowers  * Return:
19105a35163SDeven Bowers  * * %0		- Success
19205a35163SDeven Bowers  * * %-EACCES	- @ctx did not pass evaluation
19305a35163SDeven Bowers  */
19405a35163SDeven Bowers int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
19505a35163SDeven Bowers {
19605a35163SDeven Bowers 	const struct ipe_op_table *rules = NULL;
19705a35163SDeven Bowers 	const struct ipe_rule *rule = NULL;
19805a35163SDeven Bowers 	struct ipe_policy *pol = NULL;
19905a35163SDeven Bowers 	struct ipe_prop *prop = NULL;
20005a35163SDeven Bowers 	enum ipe_action_type action;
201f44554b5SDeven Bowers 	enum ipe_match match_type;
20205a35163SDeven Bowers 	bool match = false;
203a68916eaSDeven Bowers 	int rc = 0;
20405a35163SDeven Bowers 
20505a35163SDeven Bowers 	rcu_read_lock();
20605a35163SDeven Bowers 
20705a35163SDeven Bowers 	pol = rcu_dereference(ipe_active_policy);
20805a35163SDeven Bowers 	if (!pol) {
20905a35163SDeven Bowers 		rcu_read_unlock();
21005a35163SDeven Bowers 		return 0;
21105a35163SDeven Bowers 	}
21205a35163SDeven Bowers 
21305a35163SDeven Bowers 	if (ctx->op == IPE_OP_INVALID) {
214f44554b5SDeven Bowers 		if (pol->parsed->global_default_action == IPE_ACTION_INVALID) {
21505a35163SDeven Bowers 			WARN(1, "no default rule set for unknown op, ALLOW it");
216f44554b5SDeven Bowers 			action = IPE_ACTION_ALLOW;
217f44554b5SDeven Bowers 		} else {
218f44554b5SDeven Bowers 			action = pol->parsed->global_default_action;
219f44554b5SDeven Bowers 		}
220f44554b5SDeven Bowers 		match_type = IPE_MATCH_GLOBAL;
221f44554b5SDeven Bowers 		goto eval;
22205a35163SDeven Bowers 	}
22305a35163SDeven Bowers 
22405a35163SDeven Bowers 	rules = &pol->parsed->rules[ctx->op];
22505a35163SDeven Bowers 
22605a35163SDeven Bowers 	list_for_each_entry(rule, &rules->rules, next) {
22705a35163SDeven Bowers 		match = true;
22805a35163SDeven Bowers 
22905a35163SDeven Bowers 		list_for_each_entry(prop, &rule->props, next) {
23005a35163SDeven Bowers 			match = evaluate_property(ctx, prop);
23105a35163SDeven Bowers 			if (!match)
23205a35163SDeven Bowers 				break;
23305a35163SDeven Bowers 		}
23405a35163SDeven Bowers 
23505a35163SDeven Bowers 		if (match)
23605a35163SDeven Bowers 			break;
23705a35163SDeven Bowers 	}
23805a35163SDeven Bowers 
239f44554b5SDeven Bowers 	if (match) {
24005a35163SDeven Bowers 		action = rule->action;
241f44554b5SDeven Bowers 		match_type = IPE_MATCH_RULE;
242f44554b5SDeven Bowers 	} else if (rules->default_action != IPE_ACTION_INVALID) {
24305a35163SDeven Bowers 		action = rules->default_action;
244f44554b5SDeven Bowers 		match_type = IPE_MATCH_TABLE;
245f44554b5SDeven Bowers 	} else {
24605a35163SDeven Bowers 		action = pol->parsed->global_default_action;
247f44554b5SDeven Bowers 		match_type = IPE_MATCH_GLOBAL;
248f44554b5SDeven Bowers 	}
24905a35163SDeven Bowers 
250f44554b5SDeven Bowers eval:
251f44554b5SDeven Bowers 	ipe_audit_match(ctx, match_type, action, rule);
25205a35163SDeven Bowers 	rcu_read_unlock();
253f44554b5SDeven Bowers 
25405a35163SDeven Bowers 	if (action == IPE_ACTION_DENY)
255a68916eaSDeven Bowers 		rc = -EACCES;
25605a35163SDeven Bowers 
257a68916eaSDeven Bowers 	if (!READ_ONCE(enforce))
258a68916eaSDeven Bowers 		rc = 0;
259a68916eaSDeven Bowers 
260a68916eaSDeven Bowers 	return rc;
26105a35163SDeven Bowers }
262f44554b5SDeven Bowers 
263f44554b5SDeven Bowers /* Set the right module name */
264f44554b5SDeven Bowers #ifdef KBUILD_MODNAME
265f44554b5SDeven Bowers #undef KBUILD_MODNAME
266f44554b5SDeven Bowers #define KBUILD_MODNAME "ipe"
267f44554b5SDeven Bowers #endif
268f44554b5SDeven Bowers 
269f44554b5SDeven Bowers module_param(success_audit, bool, 0400);
270f44554b5SDeven Bowers MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
271a68916eaSDeven Bowers module_param(enforce, bool, 0400);
272a68916eaSDeven Bowers MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
273