File Index
Files and directories
Sign in
FILE

eval.c

File preview with syntax highlighting.

linux-6.19.14/security/ipe/eval.c C
  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
 21struct ipe_policy __rcu *ipe_active_policy;
 22bool success_audit;
 23bool 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 */
 33static 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 */
 44static 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
 50static 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
 57static 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
 63static 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 */
 74static 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
 80static 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 */
 92void 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 */
119static 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 */
134static 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
143static 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 */
159static 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 */
172static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
173{
174	return !evaluate_dmv_sig_false(ctx);
175}
176#else
177static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
178{
179	return false;
180}
181
182static 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 */
198static 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
220static 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 */
236static 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 */
252static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
253{
254	return !evaluate_fsv_sig_false(ctx);
255}
256#else
257static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
258{
259	return false;
260}
261
262static 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 */
280static 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 */
315int 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
371eval:
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
390module_param(success_audit, bool, 0400);
391MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled");
392module_param(enforce, bool, 0400);
393MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode");
~/ Read-only file preview.