xref: /linux/security/ipe/eval.c (revision a68916eaedcd01f254ac4c09ca12b5065d710fd0)
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 
14 #include "ipe.h"
15 #include "eval.h"
16 #include "policy.h"
17 #include "audit.h"
18 
19 struct ipe_policy __rcu *ipe_active_policy;
20 bool success_audit;
21 bool enforce = true;
22 
23 #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
24 
25 /**
26  * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context.
27  * @ctx: Supplies a pointer to the context to be populated.
28  * @file: Supplies the file struct of the file triggered IPE event.
29  */
30 static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file)
31 {
32 	ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
33 }
34 
35 /**
36  * ipe_build_eval_ctx() - Build an ipe evaluation context.
37  * @ctx: Supplies a pointer to the context to be populated.
38  * @file: Supplies a pointer to the file to associated with the evaluation.
39  * @op: Supplies the IPE policy operation associated with the evaluation.
40  * @hook: Supplies the LSM hook associated with the evaluation.
41  */
42 void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
43 			const struct file *file,
44 			enum ipe_op_type op,
45 			enum ipe_hook_type hook)
46 {
47 	ctx->file = file;
48 	ctx->op = op;
49 	ctx->hook = hook;
50 
51 	if (file)
52 		build_ipe_sb_ctx(ctx, file);
53 }
54 
55 /**
56  * evaluate_boot_verified() - Evaluate @ctx for the boot verified property.
57  * @ctx: Supplies a pointer to the context being evaluated.
58  *
59  * Return:
60  * * %true	- The current @ctx match the @p
61  * * %false	- The current @ctx doesn't match the @p
62  */
63 static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
64 {
65 	return ctx->initramfs;
66 }
67 
68 /**
69  * evaluate_property() - Analyze @ctx against a rule property.
70  * @ctx: Supplies a pointer to the context to be evaluated.
71  * @p: Supplies a pointer to the property to be evaluated.
72  *
73  * This function Determines whether the specified @ctx
74  * matches the conditions defined by a rule property @p.
75  *
76  * Return:
77  * * %true	- The current @ctx match the @p
78  * * %false	- The current @ctx doesn't match the @p
79  */
80 static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
81 			      struct ipe_prop *p)
82 {
83 	switch (p->type) {
84 	case IPE_PROP_BOOT_VERIFIED_FALSE:
85 		return !evaluate_boot_verified(ctx);
86 	case IPE_PROP_BOOT_VERIFIED_TRUE:
87 		return evaluate_boot_verified(ctx);
88 	default:
89 		return false;
90 	}
91 }
92 
93 /**
94  * ipe_evaluate_event() - Analyze @ctx against the current active policy.
95  * @ctx: Supplies a pointer to the context to be evaluated.
96  *
97  * This is the loop where all policy evaluations happen against the IPE policy.
98  *
99  * Return:
100  * * %0		- Success
101  * * %-EACCES	- @ctx did not pass evaluation
102  */
103 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx)
104 {
105 	const struct ipe_op_table *rules = NULL;
106 	const struct ipe_rule *rule = NULL;
107 	struct ipe_policy *pol = NULL;
108 	struct ipe_prop *prop = NULL;
109 	enum ipe_action_type action;
110 	enum ipe_match match_type;
111 	bool match = false;
112 	int rc = 0;
113 
114 	rcu_read_lock();
115 
116 	pol = rcu_dereference(ipe_active_policy);
117 	if (!pol) {
118 		rcu_read_unlock();
119 		return 0;
120 	}
121 
122 	if (ctx->op == IPE_OP_INVALID) {
123 		if (pol->parsed->global_default_action == IPE_ACTION_INVALID) {
124 			WARN(1, "no default rule set for unknown op, ALLOW it");
125 			action = IPE_ACTION_ALLOW;
126 		} else {
127 			action = pol->parsed->global_default_action;
128 		}
129 		match_type = IPE_MATCH_GLOBAL;
130 		goto eval;
131 	}
132 
133 	rules = &pol->parsed->rules[ctx->op];
134 
135 	list_for_each_entry(rule, &rules->rules, next) {
136 		match = true;
137 
138 		list_for_each_entry(prop, &rule->props, next) {
139 			match = evaluate_property(ctx, prop);
140 			if (!match)
141 				break;
142 		}
143 
144 		if (match)
145 			break;
146 	}
147 
148 	if (match) {
149 		action = rule->action;
150 		match_type = IPE_MATCH_RULE;
151 	} else if (rules->default_action != IPE_ACTION_INVALID) {
152 		action = rules->default_action;
153 		match_type = IPE_MATCH_TABLE;
154 	} else {
155 		action = pol->parsed->global_default_action;
156 		match_type = IPE_MATCH_GLOBAL;
157 	}
158 
159 eval:
160 	ipe_audit_match(ctx, match_type, action, rule);
161 	rcu_read_unlock();
162 
163 	if (action == IPE_ACTION_DENY)
164 		rc = -EACCES;
165 
166 	if (!READ_ONCE(enforce))
167 		rc = 0;
168 
169 	return rc;
170 }
171 
172 /* Set the right module name */
173 #ifdef KBUILD_MODNAME
174 #undef KBUILD_MODNAME
175 #define KBUILD_MODNAME "ipe"
176 #endif
177 
178 module_param(success_audit, bool, 0400);
179 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
180 module_param(enforce, bool, 0400);
181 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
182