Skip to content

Commit 31f8c86

Browse files
jxwufanpcmoore
authored andcommitted
ipe: enable support for fs-verity as a trust provider
Enable IPE policy authors to indicate trust for a singular fsverity file, identified by the digest information, through "fsverity_digest" and all files using valid fsverity builtin signatures via "fsverity_signature". This enables file-level integrity claims to be expressed in IPE, allowing individual files to be authorized, giving some flexibility for policy authors. Such file-level claims are important to be expressed for enforcing the integrity of packages, as well as address some of the scalability issues in a sole dm-verity based solution (# of loop back devices, etc). This solution cannot be done in userspace as the minimum threat that IPE should mitigate is an attacker downloads malicious payload with all required dependencies. These dependencies can lack the userspace check, bypassing the protection entirely. A similar attack succeeds if the userspace component is replaced with a version that does not perform the check. As a result, this can only be done in the common entry point - the kernel. Signed-off-by: Deven Bowers <[email protected]> Signed-off-by: Fan Wu <[email protected]> Signed-off-by: Paul Moore <[email protected]>
1 parent 7c373e4 commit 31f8c86

File tree

10 files changed

+237
-1
lines changed

10 files changed

+237
-1
lines changed

security/ipe/Kconfig

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ menuconfig SECURITY_IPE
1010
select SYSTEM_DATA_VERIFICATION
1111
select IPE_PROP_DM_VERITY if DM_VERITY
1212
select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
13+
select IPE_PROP_FS_VERITY if FS_VERITY
14+
select IPE_PROP_FS_VERITY_BUILTIN_SIG if FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES
1315
help
1416
This option enables the Integrity Policy Enforcement LSM
1517
allowing users to define a policy to enforce a trust-based access
@@ -39,6 +41,30 @@ config IPE_PROP_DM_VERITY_SIGNATURE
3941
volume, which has been mounted with a valid signed root hash,
4042
is evaluated.
4143

44+
If unsure, answer Y.
45+
46+
config IPE_PROP_FS_VERITY
47+
bool "Enable support for fs-verity based on file digest"
48+
depends on FS_VERITY
49+
help
50+
This option enables the 'fsverity_digest' property within IPE
51+
policies. The property evaluates to TRUE when a file is fsverity
52+
enabled and its digest matches the supplied digest value in the
53+
policy.
54+
55+
if unsure, answer Y.
56+
57+
config IPE_PROP_FS_VERITY_BUILTIN_SIG
58+
bool "Enable support for fs-verity based on builtin signature"
59+
depends on FS_VERITY && FS_VERITY_BUILTIN_SIGNATURES
60+
help
61+
This option enables the 'fsverity_signature' property within IPE
62+
policies. The property evaluates to TRUE when a file is fsverity
63+
enabled and it has a valid builtin signature whose signing cert
64+
is in the .fs-verity keyring.
65+
66+
if unsure, answer Y.
67+
4268
endmenu
4369

4470
endif

security/ipe/audit.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ static const char *const audit_prop_names[__IPE_PROP_MAX] = {
5656
"dmverity_roothash=",
5757
"dmverity_signature=FALSE",
5858
"dmverity_signature=TRUE",
59+
"fsverity_digest=",
60+
"fsverity_signature=FALSE",
61+
"fsverity_signature=TRUE",
5962
};
6063

6164
/**
@@ -69,6 +72,17 @@ static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh)
6972
ipe_digest_audit(ab, rh);
7073
}
7174

75+
/**
76+
* audit_fsv_digest() - audit the digest of a fsverity_digest property.
77+
* @ab: Supplies a pointer to the audit_buffer to append to.
78+
* @d: Supplies a pointer to the digest structure.
79+
*/
80+
static void audit_fsv_digest(struct audit_buffer *ab, const void *d)
81+
{
82+
audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]);
83+
ipe_digest_audit(ab, d);
84+
}
85+
7286
/**
7387
* audit_rule() - audit an IPE policy rule.
7488
* @ab: Supplies a pointer to the audit_buffer to append to.
@@ -85,6 +99,9 @@ static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
8599
case IPE_PROP_DMV_ROOTHASH:
86100
audit_dmv_roothash(ab, ptr->value);
87101
break;
102+
case IPE_PROP_FSV_DIGEST:
103+
audit_fsv_digest(ab, ptr->value);
104+
break;
88105
default:
89106
audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
90107
break;

security/ipe/eval.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/sched.h>
1111
#include <linux/rcupdate.h>
1212
#include <linux/moduleparam.h>
13+
#include <linux/fsverity.h>
1314

1415
#include "ipe.h"
1516
#include "eval.h"
@@ -51,6 +52,36 @@ static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *con
5152
}
5253
#endif /* CONFIG_IPE_PROP_DM_VERITY */
5354

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+
5485
/**
5586
* ipe_build_eval_ctx() - Build an ipe evaluation context.
5687
* @ctx: Supplies a pointer to the context to be populated.
@@ -63,13 +94,17 @@ void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
6394
enum ipe_op_type op,
6495
enum ipe_hook_type hook)
6596
{
97+
struct inode *ino;
98+
6699
ctx->file = file;
67100
ctx->op = op;
68101
ctx->hook = hook;
69102

70103
if (file) {
71104
build_ipe_sb_ctx(ctx, file);
72-
build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry));
105+
ino = d_real_inode(file->f_path.dentry);
106+
build_ipe_bdev_ctx(ctx, ino);
107+
build_ipe_inode_ctx(ctx, ino);
73108
}
74109
}
75110

@@ -150,6 +185,86 @@ static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
150185
}
151186
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
152187

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+
153268
/**
154269
* evaluate_property() - Analyze @ctx against a rule property.
155270
* @ctx: Supplies a pointer to the context to be evaluated.
@@ -176,6 +291,12 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
176291
return evaluate_dmv_sig_false(ctx);
177292
case IPE_PROP_DMV_SIG_TRUE:
178293
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);
179300
default:
180301
return false;
181302
}

security/ipe/eval.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ struct ipe_bdev {
3131
};
3232
#endif /* CONFIG_IPE_PROP_DM_VERITY */
3333

34+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
35+
struct ipe_inode {
36+
bool fs_verity_signed;
37+
};
38+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
39+
3440
struct ipe_eval_ctx {
3541
enum ipe_op_type op;
3642
enum ipe_hook_type hook;
@@ -40,6 +46,12 @@ struct ipe_eval_ctx {
4046
#ifdef CONFIG_IPE_PROP_DM_VERITY
4147
const struct ipe_bdev *ipe_bdev;
4248
#endif /* CONFIG_IPE_PROP_DM_VERITY */
49+
#ifdef CONFIG_IPE_PROP_FS_VERITY
50+
const struct inode *ino;
51+
#endif /* CONFIG_IPE_PROP_FS_VERITY */
52+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
53+
const struct ipe_inode *ipe_inode;
54+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
4355
};
4456

4557
enum ipe_match {

security/ipe/hooks.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,32 @@ int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type typ
283283
return -ENOMEM;
284284
}
285285
#endif /* CONFIG_IPE_PROP_DM_VERITY */
286+
287+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
288+
/**
289+
* ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob.
290+
* @inode: The inode to source the security blob from.
291+
* @type: Supplies the integrity type.
292+
* @value: The value to be stored.
293+
* @size: The size of @value.
294+
*
295+
* This hook is currently used to save the existence of a validated fs-verity
296+
* builtin signature into LSM blob.
297+
*
298+
* Return: %0 on success. If an error occurs, the function will return the
299+
* -errno.
300+
*/
301+
int ipe_inode_setintegrity(const struct inode *inode,
302+
enum lsm_integrity_type type,
303+
const void *value, size_t size)
304+
{
305+
struct ipe_inode *inode_sec = ipe_inode(inode);
306+
307+
if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) {
308+
inode_sec->fs_verity_signed = size > 0 && value;
309+
return 0;
310+
}
311+
312+
return -EINVAL;
313+
}
314+
#endif /* CONFIG_CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */

security/ipe/hooks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/binfmts.h>
1010
#include <linux/security.h>
1111
#include <linux/blk_types.h>
12+
#include <linux/fsverity.h>
1213

1314
enum ipe_hook_type {
1415
IPE_HOOK_BPRM_CHECK = 0,
@@ -43,4 +44,9 @@ int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type typ
4344
const void *value, size_t len);
4445
#endif /* CONFIG_IPE_PROP_DM_VERITY */
4546

47+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
48+
int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type type,
49+
const void *value, size_t size);
50+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
51+
4652
#endif /* _IPE_HOOKS_H */

security/ipe/ipe.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
1616
#ifdef CONFIG_IPE_PROP_DM_VERITY
1717
.lbs_bdev = sizeof(struct ipe_bdev),
1818
#endif /* CONFIG_IPE_PROP_DM_VERITY */
19+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
20+
.lbs_inode = sizeof(struct ipe_inode),
21+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
1922
};
2023

2124
static const struct lsm_id ipe_lsmid = {
@@ -35,6 +38,13 @@ struct ipe_bdev *ipe_bdev(struct block_device *b)
3538
}
3639
#endif /* CONFIG_IPE_PROP_DM_VERITY */
3740

41+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
42+
struct ipe_inode *ipe_inode(const struct inode *inode)
43+
{
44+
return inode->i_security + ipe_blobs.lbs_inode;
45+
}
46+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
47+
3848
static struct security_hook_list ipe_hooks[] __ro_after_init = {
3949
LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security),
4050
LSM_HOOK_INIT(mmap_file, ipe_mmap_file),
@@ -46,6 +56,9 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
4656
LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security),
4757
LSM_HOOK_INIT(bdev_setintegrity, ipe_bdev_setintegrity),
4858
#endif /* CONFIG_IPE_PROP_DM_VERITY */
59+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
60+
LSM_HOOK_INIT(inode_setintegrity, ipe_inode_setintegrity),
61+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
4962
};
5063

5164
/**

security/ipe/ipe.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@ extern bool ipe_enabled;
1919
#ifdef CONFIG_IPE_PROP_DM_VERITY
2020
struct ipe_bdev *ipe_bdev(struct block_device *b);
2121
#endif /* CONFIG_IPE_PROP_DM_VERITY */
22+
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
23+
struct ipe_inode *ipe_inode(const struct inode *inode);
24+
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
2225

2326
#endif /* _IPE_H */

security/ipe/policy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ enum ipe_prop_type {
3636
IPE_PROP_DMV_ROOTHASH,
3737
IPE_PROP_DMV_SIG_FALSE,
3838
IPE_PROP_DMV_SIG_TRUE,
39+
IPE_PROP_FSV_DIGEST,
40+
IPE_PROP_FSV_SIG_FALSE,
41+
IPE_PROP_FSV_SIG_TRUE,
3942
__IPE_PROP_MAX
4043
};
4144

security/ipe/policy_parser.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ static const match_table_t property_tokens = {
278278
{IPE_PROP_DMV_ROOTHASH, "dmverity_roothash=%s"},
279279
{IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"},
280280
{IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"},
281+
{IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"},
282+
{IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
283+
{IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
281284
{IPE_PROP_INVALID, NULL}
282285
};
283286

@@ -310,6 +313,7 @@ static int parse_property(char *t, struct ipe_rule *r)
310313

311314
switch (token) {
312315
case IPE_PROP_DMV_ROOTHASH:
316+
case IPE_PROP_FSV_DIGEST:
313317
dup = match_strdup(&args[0]);
314318
if (!dup) {
315319
rc = -ENOMEM;
@@ -325,6 +329,8 @@ static int parse_property(char *t, struct ipe_rule *r)
325329
case IPE_PROP_BOOT_VERIFIED_TRUE:
326330
case IPE_PROP_DMV_SIG_FALSE:
327331
case IPE_PROP_DMV_SIG_TRUE:
332+
case IPE_PROP_FSV_SIG_FALSE:
333+
case IPE_PROP_FSV_SIG_TRUE:
328334
p->type = token;
329335
break;
330336
default:

0 commit comments

Comments
 (0)