Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/ipe/eval.c
26378 views
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
*/
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
*/
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
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
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
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
*/
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
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
*/
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
*/
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
*/
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
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
*/
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
*/
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
177
static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
178
{
179
return false;
180
}
181
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
*/
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
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
*/
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
*/
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
257
static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx)
258
{
259
return false;
260
}
261
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
*/
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
*/
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
395