xref: /linux/security/ipe/eval.c (revision a68916eaedcd01f254ac4c09ca12b5065d710fd0)
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"
1805a35163SDeven Bowers 
1905a35163SDeven Bowers struct ipe_policy __rcu *ipe_active_policy;
20f44554b5SDeven Bowers bool success_audit;
21*a68916eaSDeven Bowers bool enforce = true;
2205a35163SDeven Bowers 
23a8a74df1SFan Wu #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
24a8a74df1SFan Wu 
25a8a74df1SFan Wu /**
26a8a74df1SFan Wu  * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context.
27a8a74df1SFan Wu  * @ctx: Supplies a pointer to the context to be populated.
28a8a74df1SFan Wu  * @file: Supplies the file struct of the file triggered IPE event.
29a8a74df1SFan Wu  */
30a8a74df1SFan Wu static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file)
31a8a74df1SFan Wu {
32a8a74df1SFan Wu 	ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
33a8a74df1SFan Wu }
34a8a74df1SFan Wu 
3505a35163SDeven Bowers /**
3652443cb6SDeven Bowers  * ipe_build_eval_ctx() - Build an ipe evaluation context.
3752443cb6SDeven Bowers  * @ctx: Supplies a pointer to the context to be populated.
3852443cb6SDeven Bowers  * @file: Supplies a pointer to the file to associated with the evaluation.
3952443cb6SDeven Bowers  * @op: Supplies the IPE policy operation associated with the evaluation.
40f44554b5SDeven Bowers  * @hook: Supplies the LSM hook associated with the evaluation.
4152443cb6SDeven Bowers  */
4252443cb6SDeven Bowers void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
4352443cb6SDeven Bowers 			const struct file *file,
44f44554b5SDeven Bowers 			enum ipe_op_type op,
45f44554b5SDeven Bowers 			enum ipe_hook_type hook)
4652443cb6SDeven Bowers {
4752443cb6SDeven Bowers 	ctx->file = file;
4852443cb6SDeven Bowers 	ctx->op = op;
49f44554b5SDeven Bowers 	ctx->hook = hook;
50a8a74df1SFan Wu 
51a8a74df1SFan Wu 	if (file)
52a8a74df1SFan Wu 		build_ipe_sb_ctx(ctx, file);
53a8a74df1SFan Wu }
54a8a74df1SFan Wu 
55a8a74df1SFan Wu /**
56a8a74df1SFan Wu  * evaluate_boot_verified() - Evaluate @ctx for the boot verified property.
57a8a74df1SFan Wu  * @ctx: Supplies a pointer to the context being evaluated.
58a8a74df1SFan Wu  *
59a8a74df1SFan Wu  * Return:
60a8a74df1SFan Wu  * * %true	- The current @ctx match the @p
61a8a74df1SFan Wu  * * %false	- The current @ctx doesn't match the @p
62a8a74df1SFan Wu  */
63a8a74df1SFan Wu static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
64a8a74df1SFan Wu {
65a8a74df1SFan Wu 	return ctx->initramfs;
6652443cb6SDeven Bowers }
6752443cb6SDeven Bowers 
6852443cb6SDeven Bowers /**
6905a35163SDeven Bowers  * evaluate_property() - Analyze @ctx against a rule property.
7005a35163SDeven Bowers  * @ctx: Supplies a pointer to the context to be evaluated.
7105a35163SDeven Bowers  * @p: Supplies a pointer to the property to be evaluated.
7205a35163SDeven Bowers  *
73a8a74df1SFan Wu  * This function Determines whether the specified @ctx
74a8a74df1SFan Wu  * matches the conditions defined by a rule property @p.
7505a35163SDeven Bowers  *
7605a35163SDeven Bowers  * Return:
7705a35163SDeven Bowers  * * %true	- The current @ctx match the @p
7805a35163SDeven Bowers  * * %false	- The current @ctx doesn't match the @p
7905a35163SDeven Bowers  */
8005a35163SDeven Bowers static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
8105a35163SDeven Bowers 			      struct ipe_prop *p)
8205a35163SDeven Bowers {
83a8a74df1SFan Wu 	switch (p->type) {
84a8a74df1SFan Wu 	case IPE_PROP_BOOT_VERIFIED_FALSE:
85a8a74df1SFan Wu 		return !evaluate_boot_verified(ctx);
86a8a74df1SFan Wu 	case IPE_PROP_BOOT_VERIFIED_TRUE:
87a8a74df1SFan Wu 		return evaluate_boot_verified(ctx);
88a8a74df1SFan Wu 	default:
8905a35163SDeven Bowers 		return false;
9005a35163SDeven Bowers 	}
91a8a74df1SFan Wu }
9205a35163SDeven Bowers 
9305a35163SDeven Bowers /**
9405a35163SDeven Bowers  * ipe_evaluate_event() - Analyze @ctx against the current active policy.
9505a35163SDeven Bowers  * @ctx: Supplies a pointer to the context to be evaluated.
9605a35163SDeven Bowers  *
9705a35163SDeven Bowers  * This is the loop where all policy evaluations happen against the IPE policy.
9805a35163SDeven Bowers  *
9905a35163SDeven Bowers  * Return:
10005a35163SDeven Bowers  * * %0		- Success
10105a35163SDeven Bowers  * * %-EACCES	- @ctx did not pass evaluation
10205a35163SDeven Bowers  */
10305a35163SDeven Bowers int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
10405a35163SDeven Bowers {
10505a35163SDeven Bowers 	const struct ipe_op_table *rules = NULL;
10605a35163SDeven Bowers 	const struct ipe_rule *rule = NULL;
10705a35163SDeven Bowers 	struct ipe_policy *pol = NULL;
10805a35163SDeven Bowers 	struct ipe_prop *prop = NULL;
10905a35163SDeven Bowers 	enum ipe_action_type action;
110f44554b5SDeven Bowers 	enum ipe_match match_type;
11105a35163SDeven Bowers 	bool match = false;
112*a68916eaSDeven Bowers 	int rc = 0;
11305a35163SDeven Bowers 
11405a35163SDeven Bowers 	rcu_read_lock();
11505a35163SDeven Bowers 
11605a35163SDeven Bowers 	pol = rcu_dereference(ipe_active_policy);
11705a35163SDeven Bowers 	if (!pol) {
11805a35163SDeven Bowers 		rcu_read_unlock();
11905a35163SDeven Bowers 		return 0;
12005a35163SDeven Bowers 	}
12105a35163SDeven Bowers 
12205a35163SDeven Bowers 	if (ctx->op == IPE_OP_INVALID) {
123f44554b5SDeven Bowers 		if (pol->parsed->global_default_action == IPE_ACTION_INVALID) {
12405a35163SDeven Bowers 			WARN(1, "no default rule set for unknown op, ALLOW it");
125f44554b5SDeven Bowers 			action = IPE_ACTION_ALLOW;
126f44554b5SDeven Bowers 		} else {
127f44554b5SDeven Bowers 			action = pol->parsed->global_default_action;
128f44554b5SDeven Bowers 		}
129f44554b5SDeven Bowers 		match_type = IPE_MATCH_GLOBAL;
130f44554b5SDeven Bowers 		goto eval;
13105a35163SDeven Bowers 	}
13205a35163SDeven Bowers 
13305a35163SDeven Bowers 	rules = &pol->parsed->rules[ctx->op];
13405a35163SDeven Bowers 
13505a35163SDeven Bowers 	list_for_each_entry(rule, &rules->rules, next) {
13605a35163SDeven Bowers 		match = true;
13705a35163SDeven Bowers 
13805a35163SDeven Bowers 		list_for_each_entry(prop, &rule->props, next) {
13905a35163SDeven Bowers 			match = evaluate_property(ctx, prop);
14005a35163SDeven Bowers 			if (!match)
14105a35163SDeven Bowers 				break;
14205a35163SDeven Bowers 		}
14305a35163SDeven Bowers 
14405a35163SDeven Bowers 		if (match)
14505a35163SDeven Bowers 			break;
14605a35163SDeven Bowers 	}
14705a35163SDeven Bowers 
148f44554b5SDeven Bowers 	if (match) {
14905a35163SDeven Bowers 		action = rule->action;
150f44554b5SDeven Bowers 		match_type = IPE_MATCH_RULE;
151f44554b5SDeven Bowers 	} else if (rules->default_action != IPE_ACTION_INVALID) {
15205a35163SDeven Bowers 		action = rules->default_action;
153f44554b5SDeven Bowers 		match_type = IPE_MATCH_TABLE;
154f44554b5SDeven Bowers 	} else {
15505a35163SDeven Bowers 		action = pol->parsed->global_default_action;
156f44554b5SDeven Bowers 		match_type = IPE_MATCH_GLOBAL;
157f44554b5SDeven Bowers 	}
15805a35163SDeven Bowers 
159f44554b5SDeven Bowers eval:
160f44554b5SDeven Bowers 	ipe_audit_match(ctx, match_type, action, rule);
16105a35163SDeven Bowers 	rcu_read_unlock();
162f44554b5SDeven Bowers 
16305a35163SDeven Bowers 	if (action == IPE_ACTION_DENY)
164*a68916eaSDeven Bowers 		rc = -EACCES;
16505a35163SDeven Bowers 
166*a68916eaSDeven Bowers 	if (!READ_ONCE(enforce))
167*a68916eaSDeven Bowers 		rc = 0;
168*a68916eaSDeven Bowers 
169*a68916eaSDeven Bowers 	return rc;
17005a35163SDeven Bowers }
171f44554b5SDeven Bowers 
172f44554b5SDeven Bowers /* Set the right module name */
173f44554b5SDeven Bowers #ifdef KBUILD_MODNAME
174f44554b5SDeven Bowers #undef KBUILD_MODNAME
175f44554b5SDeven Bowers #define KBUILD_MODNAME "ipe"
176f44554b5SDeven Bowers #endif
177f44554b5SDeven Bowers 
178f44554b5SDeven Bowers module_param(success_audit, bool, 0400);
179f44554b5SDeven Bowers MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
180*a68916eaSDeven Bowers module_param(enforce, bool, 0400);
181*a68916eaSDeven Bowers MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
182