Skip to content

Commit e155858

Browse files
bowerscd-corppcmoore
authored andcommitted
ipe: add support for dm-verity as a trust provider
Allows author of IPE policy to indicate trust for a singular dm-verity volume, identified by roothash, through "dmverity_roothash" and all signed and validated dm-verity volumes, through "dmverity_signature". Signed-off-by: Deven Bowers <[email protected]> Signed-off-by: Fan Wu <[email protected]> [PM: fixed some line length issues in the comments] Signed-off-by: Paul Moore <[email protected]>
1 parent a6af7bc commit e155858

File tree

14 files changed

+460
-15
lines changed

14 files changed

+460
-15
lines changed

security/ipe/Kconfig

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,37 @@ menuconfig SECURITY_IPE
88
depends on SECURITY && SECURITYFS && AUDIT && AUDITSYSCALL
99
select PKCS7_MESSAGE_PARSER
1010
select SYSTEM_DATA_VERIFICATION
11+
select IPE_PROP_DM_VERITY if DM_VERITY
12+
select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
1113
help
1214
This option enables the Integrity Policy Enforcement LSM
1315
allowing users to define a policy to enforce a trust-based access
1416
control. A key feature of IPE is a customizable policy to allow
1517
admins to reconfigure trust requirements on the fly.
1618

1719
If unsure, answer N.
20+
21+
if SECURITY_IPE
22+
menu "IPE Trust Providers"
23+
24+
config IPE_PROP_DM_VERITY
25+
bool "Enable support for dm-verity based on root hash"
26+
depends on DM_VERITY
27+
help
28+
This option enables the 'dmverity_roothash' property within IPE
29+
policies. The property evaluates to TRUE when a file from a dm-verity
30+
volume is evaluated, and the volume's root hash matches the value
31+
supplied in the policy.
32+
33+
config IPE_PROP_DM_VERITY_SIGNATURE
34+
bool "Enable support for dm-verity based on root hash signature"
35+
depends on DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
36+
help
37+
This option enables the 'dmverity_signature' property within IPE
38+
policies. The property evaluates to TRUE when a file from a dm-verity
39+
volume, which has been mounted with a valid signed root hash,
40+
is evaluated.
41+
42+
endmenu
43+
44+
endif

security/ipe/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#
77

88
obj-$(CONFIG_SECURITY_IPE) += \
9+
digest.o \
910
eval.o \
1011
hooks.o \
1112
fs.o \

security/ipe/audit.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "hooks.h"
1414
#include "policy.h"
1515
#include "audit.h"
16+
#include "digest.h"
1617

1718
#define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY")
1819

@@ -52,8 +53,22 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
5253
static const char *const audit_prop_names[__IPE_PROP_MAX] = {
5354
"boot_verified=FALSE",
5455
"boot_verified=TRUE",
56+
"dmverity_roothash=",
57+
"dmverity_signature=FALSE",
58+
"dmverity_signature=TRUE",
5559
};
5660

61+
/**
62+
* audit_dmv_roothash() - audit the roothash of a dmverity_roothash property.
63+
* @ab: Supplies a pointer to the audit_buffer to append to.
64+
* @rh: Supplies a pointer to the digest structure.
65+
*/
66+
static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh)
67+
{
68+
audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_DMV_ROOTHASH]);
69+
ipe_digest_audit(ab, rh);
70+
}
71+
5772
/**
5873
* audit_rule() - audit an IPE policy rule.
5974
* @ab: Supplies a pointer to the audit_buffer to append to.
@@ -65,8 +80,18 @@ static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
6580

6681
audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]);
6782

68-
list_for_each_entry(ptr, &r->props, next)
69-
audit_log_format(ab, "%s ", audit_prop_names[ptr->type]);
83+
list_for_each_entry(ptr, &r->props, next) {
84+
switch (ptr->type) {
85+
case IPE_PROP_DMV_ROOTHASH:
86+
audit_dmv_roothash(ab, ptr->value);
87+
break;
88+
default:
89+
audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
90+
break;
91+
}
92+
93+
audit_log_format(ab, " ");
94+
}
7095

7196
audit_log_format(ab, "action=%s\"", ACTSTR(r->action));
7297
}

security/ipe/digest.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4+
*/
5+
6+
#include "digest.h"
7+
8+
/**
9+
* ipe_digest_parse() - parse a digest in IPE's policy.
10+
* @valstr: Supplies the string parsed from the policy.
11+
*
12+
* Digests in IPE are defined in a standard way:
13+
* <alg_name>:<hex>
14+
*
15+
* Use this function to create a property to parse the digest
16+
* consistently. The parsed digest will be saved in @value in IPE's
17+
* policy.
18+
*
19+
* Return: The parsed digest_info structure on success. If an error occurs,
20+
* the function will return the error value (via ERR_PTR).
21+
*/
22+
struct digest_info *ipe_digest_parse(const char *valstr)
23+
{
24+
struct digest_info *info = NULL;
25+
char *sep, *raw_digest;
26+
size_t raw_digest_len;
27+
u8 *digest = NULL;
28+
char *alg = NULL;
29+
int rc = 0;
30+
31+
info = kzalloc(sizeof(*info), GFP_KERNEL);
32+
if (!info)
33+
return ERR_PTR(-ENOMEM);
34+
35+
sep = strchr(valstr, ':');
36+
if (!sep) {
37+
rc = -EBADMSG;
38+
goto err;
39+
}
40+
41+
alg = kstrndup(valstr, sep - valstr, GFP_KERNEL);
42+
if (!alg) {
43+
rc = -ENOMEM;
44+
goto err;
45+
}
46+
47+
raw_digest = sep + 1;
48+
raw_digest_len = strlen(raw_digest);
49+
50+
info->digest_len = (raw_digest_len + 1) / 2;
51+
digest = kzalloc(info->digest_len, GFP_KERNEL);
52+
if (!digest) {
53+
rc = -ENOMEM;
54+
goto err;
55+
}
56+
57+
rc = hex2bin(digest, raw_digest, info->digest_len);
58+
if (rc < 0) {
59+
rc = -EINVAL;
60+
goto err;
61+
}
62+
63+
info->alg = alg;
64+
info->digest = digest;
65+
return info;
66+
67+
err:
68+
kfree(alg);
69+
kfree(digest);
70+
kfree(info);
71+
return ERR_PTR(rc);
72+
}
73+
74+
/**
75+
* ipe_digest_eval() - evaluate an IPE digest against another digest.
76+
* @expected: Supplies the policy-provided digest value.
77+
* @digest: Supplies the digest to compare against the policy digest value.
78+
*
79+
* Return:
80+
* * %true - digests match
81+
* * %false - digests do not match
82+
*/
83+
bool ipe_digest_eval(const struct digest_info *expected,
84+
const struct digest_info *digest)
85+
{
86+
return (expected->digest_len == digest->digest_len) &&
87+
(!strcmp(expected->alg, digest->alg)) &&
88+
(!memcmp(expected->digest, digest->digest, expected->digest_len));
89+
}
90+
91+
/**
92+
* ipe_digest_free() - free an IPE digest.
93+
* @info: Supplies a pointer the policy-provided digest to free.
94+
*/
95+
void ipe_digest_free(struct digest_info *info)
96+
{
97+
if (IS_ERR_OR_NULL(info))
98+
return;
99+
100+
kfree(info->alg);
101+
kfree(info->digest);
102+
kfree(info);
103+
}
104+
105+
/**
106+
* ipe_digest_audit() - audit a digest that was sourced from IPE's policy.
107+
* @ab: Supplies the audit_buffer to append the formatted result.
108+
* @info: Supplies a pointer to source the audit record from.
109+
*
110+
* Digests in IPE are audited in this format:
111+
* <alg_name>:<hex>
112+
*/
113+
void ipe_digest_audit(struct audit_buffer *ab, const struct digest_info *info)
114+
{
115+
audit_log_untrustedstring(ab, info->alg);
116+
audit_log_format(ab, ":");
117+
audit_log_n_hex(ab, info->digest, info->digest_len);
118+
}

security/ipe/digest.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4+
*/
5+
6+
#ifndef _IPE_DIGEST_H
7+
#define _IPE_DIGEST_H
8+
9+
#include <linux/types.h>
10+
#include <linux/audit.h>
11+
12+
#include "policy.h"
13+
14+
struct digest_info {
15+
const char *alg;
16+
const u8 *digest;
17+
size_t digest_len;
18+
};
19+
20+
struct digest_info *ipe_digest_parse(const char *valstr);
21+
void ipe_digest_free(struct digest_info *digest_info);
22+
void ipe_digest_audit(struct audit_buffer *ab, const struct digest_info *val);
23+
bool ipe_digest_eval(const struct digest_info *expected,
24+
const struct digest_info *digest);
25+
26+
#endif /* _IPE_DIGEST_H */

security/ipe/eval.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
#include "eval.h"
1616
#include "policy.h"
1717
#include "audit.h"
18+
#include "digest.h"
1819

1920
struct ipe_policy __rcu *ipe_active_policy;
2021
bool success_audit;
2122
bool enforce = true;
23+
#define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev)
2224

2325
#define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
2426

@@ -32,6 +34,23 @@ static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const
3234
ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
3335
}
3436

37+
#ifdef CONFIG_IPE_PROP_DM_VERITY
38+
/**
39+
* build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context.
40+
* @ctx: Supplies a pointer to the context to be populated.
41+
* @ino: Supplies the inode struct of the file triggered IPE event.
42+
*/
43+
static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
44+
{
45+
if (INO_BLOCK_DEV(ino))
46+
ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino));
47+
}
48+
#else
49+
static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
50+
{
51+
}
52+
#endif /* CONFIG_IPE_PROP_DM_VERITY */
53+
3554
/**
3655
* ipe_build_eval_ctx() - Build an ipe evaluation context.
3756
* @ctx: Supplies a pointer to the context to be populated.
@@ -48,8 +67,10 @@ void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
4867
ctx->op = op;
4968
ctx->hook = hook;
5069

51-
if (file)
70+
if (file) {
5271
build_ipe_sb_ctx(ctx, file);
72+
build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry));
73+
}
5374
}
5475

5576
/**
@@ -65,6 +86,70 @@ static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
6586
return ctx->initramfs;
6687
}
6788

89+
#ifdef CONFIG_IPE_PROP_DM_VERITY
90+
/**
91+
* evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property.
92+
* @ctx: Supplies a pointer to the context being evaluated.
93+
* @p: Supplies a pointer to the property being evaluated.
94+
*
95+
* Return:
96+
* * %true - The current @ctx match the @p
97+
* * %false - The current @ctx doesn't match the @p
98+
*/
99+
static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
100+
struct ipe_prop *p)
101+
{
102+
return !!ctx->ipe_bdev &&
103+
!!ctx->ipe_bdev->root_hash &&
104+
ipe_digest_eval(p->value,
105+
ctx->ipe_bdev->root_hash);
106+
}
107+
#else
108+
static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
109+
struct ipe_prop *p)
110+
{
111+
return false;
112+
}
113+
#endif /* CONFIG_IPE_PROP_DM_VERITY */
114+
115+
#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
116+
/**
117+
* evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property.
118+
* @ctx: Supplies a pointer to the context being evaluated.
119+
*
120+
* Return:
121+
* * %true - The current @ctx match the property
122+
* * %false - The current @ctx doesn't match the property
123+
*/
124+
static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
125+
{
126+
return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed);
127+
}
128+
129+
/**
130+
* evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property.
131+
* @ctx: Supplies a pointer to the context being evaluated.
132+
*
133+
* Return:
134+
* * %true - The current @ctx match the property
135+
* * %false - The current @ctx doesn't match the property
136+
*/
137+
static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
138+
{
139+
return !evaluate_dmv_sig_false(ctx);
140+
}
141+
#else
142+
static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
143+
{
144+
return false;
145+
}
146+
147+
static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
148+
{
149+
return false;
150+
}
151+
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
152+
68153
/**
69154
* evaluate_property() - Analyze @ctx against a rule property.
70155
* @ctx: Supplies a pointer to the context to be evaluated.
@@ -85,6 +170,12 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
85170
return !evaluate_boot_verified(ctx);
86171
case IPE_PROP_BOOT_VERIFIED_TRUE:
87172
return evaluate_boot_verified(ctx);
173+
case IPE_PROP_DMV_ROOTHASH:
174+
return evaluate_dmv_roothash(ctx, p);
175+
case IPE_PROP_DMV_SIG_FALSE:
176+
return evaluate_dmv_sig_false(ctx);
177+
case IPE_PROP_DMV_SIG_TRUE:
178+
return evaluate_dmv_sig_true(ctx);
88179
default:
89180
return false;
90181
}

0 commit comments

Comments
 (0)