Commit e155858d authored by Deven Bowers's avatar Deven Bowers Committed by Paul Moore

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: default avatarDeven Bowers <deven.desai@linux.microsoft.com>
Signed-off-by: default avatarFan Wu <wufan@linux.microsoft.com>
[PM: fixed some line length issues in the comments]
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent a6af7bc3
...@@ -8,6 +8,8 @@ menuconfig SECURITY_IPE ...@@ -8,6 +8,8 @@ menuconfig SECURITY_IPE
depends on SECURITY && SECURITYFS && AUDIT && AUDITSYSCALL depends on SECURITY && SECURITYFS && AUDIT && AUDITSYSCALL
select PKCS7_MESSAGE_PARSER select PKCS7_MESSAGE_PARSER
select SYSTEM_DATA_VERIFICATION select SYSTEM_DATA_VERIFICATION
select IPE_PROP_DM_VERITY if DM_VERITY
select IPE_PROP_DM_VERITY_SIGNATURE if DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
help help
This option enables the Integrity Policy Enforcement LSM This option enables the Integrity Policy Enforcement LSM
allowing users to define a policy to enforce a trust-based access allowing users to define a policy to enforce a trust-based access
...@@ -15,3 +17,28 @@ menuconfig SECURITY_IPE ...@@ -15,3 +17,28 @@ menuconfig SECURITY_IPE
admins to reconfigure trust requirements on the fly. admins to reconfigure trust requirements on the fly.
If unsure, answer N. If unsure, answer N.
if SECURITY_IPE
menu "IPE Trust Providers"
config IPE_PROP_DM_VERITY
bool "Enable support for dm-verity based on root hash"
depends on DM_VERITY
help
This option enables the 'dmverity_roothash' property within IPE
policies. The property evaluates to TRUE when a file from a dm-verity
volume is evaluated, and the volume's root hash matches the value
supplied in the policy.
config IPE_PROP_DM_VERITY_SIGNATURE
bool "Enable support for dm-verity based on root hash signature"
depends on DM_VERITY && DM_VERITY_VERIFY_ROOTHASH_SIG
help
This option enables the 'dmverity_signature' property within IPE
policies. The property evaluates to TRUE when a file from a dm-verity
volume, which has been mounted with a valid signed root hash,
is evaluated.
endmenu
endif
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
# #
obj-$(CONFIG_SECURITY_IPE) += \ obj-$(CONFIG_SECURITY_IPE) += \
digest.o \
eval.o \ eval.o \
hooks.o \ hooks.o \
fs.o \ fs.o \
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "hooks.h" #include "hooks.h"
#include "policy.h" #include "policy.h"
#include "audit.h" #include "audit.h"
#include "digest.h"
#define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY") #define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY")
...@@ -52,8 +53,22 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = { ...@@ -52,8 +53,22 @@ static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
static const char *const audit_prop_names[__IPE_PROP_MAX] = { static const char *const audit_prop_names[__IPE_PROP_MAX] = {
"boot_verified=FALSE", "boot_verified=FALSE",
"boot_verified=TRUE", "boot_verified=TRUE",
"dmverity_roothash=",
"dmverity_signature=FALSE",
"dmverity_signature=TRUE",
}; };
/**
* audit_dmv_roothash() - audit the roothash of a dmverity_roothash property.
* @ab: Supplies a pointer to the audit_buffer to append to.
* @rh: Supplies a pointer to the digest structure.
*/
static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh)
{
audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_DMV_ROOTHASH]);
ipe_digest_audit(ab, rh);
}
/** /**
* audit_rule() - audit an IPE policy rule. * audit_rule() - audit an IPE policy rule.
* @ab: Supplies a pointer to the audit_buffer to append to. * @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) ...@@ -65,8 +80,18 @@ static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]); audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]);
list_for_each_entry(ptr, &r->props, next) list_for_each_entry(ptr, &r->props, next) {
audit_log_format(ab, "%s ", audit_prop_names[ptr->type]); switch (ptr->type) {
case IPE_PROP_DMV_ROOTHASH:
audit_dmv_roothash(ab, ptr->value);
break;
default:
audit_log_format(ab, "%s", audit_prop_names[ptr->type]);
break;
}
audit_log_format(ab, " ");
}
audit_log_format(ab, "action=%s\"", ACTSTR(r->action)); audit_log_format(ab, "action=%s\"", ACTSTR(r->action));
} }
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
*/
#include "digest.h"
/**
* ipe_digest_parse() - parse a digest in IPE's policy.
* @valstr: Supplies the string parsed from the policy.
*
* Digests in IPE are defined in a standard way:
* <alg_name>:<hex>
*
* Use this function to create a property to parse the digest
* consistently. The parsed digest will be saved in @value in IPE's
* policy.
*
* Return: The parsed digest_info structure on success. If an error occurs,
* the function will return the error value (via ERR_PTR).
*/
struct digest_info *ipe_digest_parse(const char *valstr)
{
struct digest_info *info = NULL;
char *sep, *raw_digest;
size_t raw_digest_len;
u8 *digest = NULL;
char *alg = NULL;
int rc = 0;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return ERR_PTR(-ENOMEM);
sep = strchr(valstr, ':');
if (!sep) {
rc = -EBADMSG;
goto err;
}
alg = kstrndup(valstr, sep - valstr, GFP_KERNEL);
if (!alg) {
rc = -ENOMEM;
goto err;
}
raw_digest = sep + 1;
raw_digest_len = strlen(raw_digest);
info->digest_len = (raw_digest_len + 1) / 2;
digest = kzalloc(info->digest_len, GFP_KERNEL);
if (!digest) {
rc = -ENOMEM;
goto err;
}
rc = hex2bin(digest, raw_digest, info->digest_len);
if (rc < 0) {
rc = -EINVAL;
goto err;
}
info->alg = alg;
info->digest = digest;
return info;
err:
kfree(alg);
kfree(digest);
kfree(info);
return ERR_PTR(rc);
}
/**
* ipe_digest_eval() - evaluate an IPE digest against another digest.
* @expected: Supplies the policy-provided digest value.
* @digest: Supplies the digest to compare against the policy digest value.
*
* Return:
* * %true - digests match
* * %false - digests do not match
*/
bool ipe_digest_eval(const struct digest_info *expected,
const struct digest_info *digest)
{
return (expected->digest_len == digest->digest_len) &&
(!strcmp(expected->alg, digest->alg)) &&
(!memcmp(expected->digest, digest->digest, expected->digest_len));
}
/**
* ipe_digest_free() - free an IPE digest.
* @info: Supplies a pointer the policy-provided digest to free.
*/
void ipe_digest_free(struct digest_info *info)
{
if (IS_ERR_OR_NULL(info))
return;
kfree(info->alg);
kfree(info->digest);
kfree(info);
}
/**
* ipe_digest_audit() - audit a digest that was sourced from IPE's policy.
* @ab: Supplies the audit_buffer to append the formatted result.
* @info: Supplies a pointer to source the audit record from.
*
* Digests in IPE are audited in this format:
* <alg_name>:<hex>
*/
void ipe_digest_audit(struct audit_buffer *ab, const struct digest_info *info)
{
audit_log_untrustedstring(ab, info->alg);
audit_log_format(ab, ":");
audit_log_n_hex(ab, info->digest, info->digest_len);
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
*/
#ifndef _IPE_DIGEST_H
#define _IPE_DIGEST_H
#include <linux/types.h>
#include <linux/audit.h>
#include "policy.h"
struct digest_info {
const char *alg;
const u8 *digest;
size_t digest_len;
};
struct digest_info *ipe_digest_parse(const char *valstr);
void ipe_digest_free(struct digest_info *digest_info);
void ipe_digest_audit(struct audit_buffer *ab, const struct digest_info *val);
bool ipe_digest_eval(const struct digest_info *expected,
const struct digest_info *digest);
#endif /* _IPE_DIGEST_H */
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
#include "eval.h" #include "eval.h"
#include "policy.h" #include "policy.h"
#include "audit.h" #include "audit.h"
#include "digest.h"
struct ipe_policy __rcu *ipe_active_policy; struct ipe_policy __rcu *ipe_active_policy;
bool success_audit; bool success_audit;
bool enforce = true; bool enforce = true;
#define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev)
#define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb)
...@@ -32,6 +34,23 @@ static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const ...@@ -32,6 +34,23 @@ static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const
ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs; ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs;
} }
#ifdef CONFIG_IPE_PROP_DM_VERITY
/**
* build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context.
* @ctx: Supplies a pointer to the context to be populated.
* @ino: Supplies the inode struct of the file triggered IPE event.
*/
static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
{
if (INO_BLOCK_DEV(ino))
ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino));
}
#else
static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
{
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
/** /**
* ipe_build_eval_ctx() - Build an ipe evaluation context. * ipe_build_eval_ctx() - Build an ipe evaluation context.
* @ctx: Supplies a pointer to the context to be populated. * @ctx: Supplies a pointer to the context to be populated.
...@@ -48,8 +67,10 @@ void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx, ...@@ -48,8 +67,10 @@ void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx,
ctx->op = op; ctx->op = op;
ctx->hook = hook; ctx->hook = hook;
if (file) if (file) {
build_ipe_sb_ctx(ctx, file); build_ipe_sb_ctx(ctx, file);
build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry));
}
} }
/** /**
...@@ -65,6 +86,70 @@ static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx) ...@@ -65,6 +86,70 @@ static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx)
return ctx->initramfs; return ctx->initramfs;
} }
#ifdef CONFIG_IPE_PROP_DM_VERITY
/**
* evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property.
* @ctx: Supplies a pointer to the context being evaluated.
* @p: Supplies a pointer to the property being evaluated.
*
* Return:
* * %true - The current @ctx match the @p
* * %false - The current @ctx doesn't match the @p
*/
static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
struct ipe_prop *p)
{
return !!ctx->ipe_bdev &&
!!ctx->ipe_bdev->root_hash &&
ipe_digest_eval(p->value,
ctx->ipe_bdev->root_hash);
}
#else
static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx,
struct ipe_prop *p)
{
return false;
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
/**
* evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property.
* @ctx: Supplies a pointer to the context being evaluated.
*
* Return:
* * %true - The current @ctx match the property
* * %false - The current @ctx doesn't match the property
*/
static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
{
return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed);
}
/**
* evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property.
* @ctx: Supplies a pointer to the context being evaluated.
*
* Return:
* * %true - The current @ctx match the property
* * %false - The current @ctx doesn't match the property
*/
static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
{
return !evaluate_dmv_sig_false(ctx);
}
#else
static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx)
{
return false;
}
static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx)
{
return false;
}
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
/** /**
* evaluate_property() - Analyze @ctx against a rule property. * evaluate_property() - Analyze @ctx against a rule property.
* @ctx: Supplies a pointer to the context to be evaluated. * @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, ...@@ -85,6 +170,12 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
return !evaluate_boot_verified(ctx); return !evaluate_boot_verified(ctx);
case IPE_PROP_BOOT_VERIFIED_TRUE: case IPE_PROP_BOOT_VERIFIED_TRUE:
return evaluate_boot_verified(ctx); return evaluate_boot_verified(ctx);
case IPE_PROP_DMV_ROOTHASH:
return evaluate_dmv_roothash(ctx, p);
case IPE_PROP_DMV_SIG_FALSE:
return evaluate_dmv_sig_false(ctx);
case IPE_PROP_DMV_SIG_TRUE:
return evaluate_dmv_sig_true(ctx);
default: default:
return false; return false;
} }
......
...@@ -22,12 +22,24 @@ struct ipe_superblock { ...@@ -22,12 +22,24 @@ struct ipe_superblock {
bool initramfs; bool initramfs;
}; };
#ifdef CONFIG_IPE_PROP_DM_VERITY
struct ipe_bdev {
#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
bool dm_verity_signed;
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
struct digest_info *root_hash;
};
#endif /* CONFIG_IPE_PROP_DM_VERITY */
struct ipe_eval_ctx { struct ipe_eval_ctx {
enum ipe_op_type op; enum ipe_op_type op;
enum ipe_hook_type hook; enum ipe_hook_type hook;
const struct file *file; const struct file *file;
bool initramfs; bool initramfs;
#ifdef CONFIG_IPE_PROP_DM_VERITY
const struct ipe_bdev *ipe_bdev;
#endif /* CONFIG_IPE_PROP_DM_VERITY */
}; };
enum ipe_match { enum ipe_match {
......
...@@ -8,10 +8,12 @@ ...@@ -8,10 +8,12 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/blk_types.h>
#include "ipe.h" #include "ipe.h"
#include "hooks.h" #include "hooks.h"
#include "eval.h" #include "eval.h"
#include "digest.h"
/** /**
* ipe_bprm_check_security() - ipe security hook function for bprm check. * ipe_bprm_check_security() - ipe security hook function for bprm check.
...@@ -191,3 +193,93 @@ void ipe_unpack_initramfs(void) ...@@ -191,3 +193,93 @@ void ipe_unpack_initramfs(void)
{ {
ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true; ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true;
} }
#ifdef CONFIG_IPE_PROP_DM_VERITY
/**
* ipe_bdev_free_security() - Free IPE's LSM blob of block_devices.
* @bdev: Supplies a pointer to a block_device that contains the structure
* to free.
*/
void ipe_bdev_free_security(struct block_device *bdev)
{
struct ipe_bdev *blob = ipe_bdev(bdev);
ipe_digest_free(blob->root_hash);
}
#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
static void ipe_set_dmverity_signature(struct ipe_bdev *blob,
const void *value,
size_t size)
{
blob->dm_verity_signed = size > 0 && value;
}
#else
static inline void ipe_set_dmverity_signature(struct ipe_bdev *blob,
const void *value,
size_t size)
{
}
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
/**
* ipe_bdev_setintegrity() - Save integrity data from a bdev to IPE's LSM blob.
* @bdev: Supplies a pointer to a block_device that contains the LSM blob.
* @type: Supplies the integrity type.
* @value: Supplies the value to store.
* @size: The size of @value.
*
* This hook is currently used to save dm-verity's root hash or the existence
* of a validated signed dm-verity root hash into LSM blob.
*
* Return: %0 on success. If an error occurs, the function will return the
* -errno.
*/
int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type,
const void *value, size_t size)
{
const struct dm_verity_digest *digest = NULL;
struct ipe_bdev *blob = ipe_bdev(bdev);
struct digest_info *info = NULL;
if (type == LSM_INT_DMVERITY_SIG_VALID) {
ipe_set_dmverity_signature(blob, value, size);
return 0;
}
if (type != LSM_INT_DMVERITY_ROOTHASH)
return -EINVAL;
if (!value) {
ipe_digest_free(blob->root_hash);
blob->root_hash = NULL;
return 0;
}
digest = value;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL);
if (!info->digest)
goto err;
info->alg = kstrdup(digest->alg, GFP_KERNEL);
if (!info->alg)
goto err;
info->digest_len = digest->digest_len;
ipe_digest_free(blob->root_hash);
blob->root_hash = info;
return 0;
err:
ipe_digest_free(info);
return -ENOMEM;
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/blk_types.h>
enum ipe_hook_type { enum ipe_hook_type {
IPE_HOOK_BPRM_CHECK = 0, IPE_HOOK_BPRM_CHECK = 0,
...@@ -35,4 +36,11 @@ int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents); ...@@ -35,4 +36,11 @@ int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents);
void ipe_unpack_initramfs(void); void ipe_unpack_initramfs(void);
#ifdef CONFIG_IPE_PROP_DM_VERITY
void ipe_bdev_free_security(struct block_device *bdev);
int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type,
const void *value, size_t len);
#endif /* CONFIG_IPE_PROP_DM_VERITY */
#endif /* _IPE_HOOKS_H */ #endif /* _IPE_HOOKS_H */
...@@ -7,11 +7,15 @@ ...@@ -7,11 +7,15 @@
#include "ipe.h" #include "ipe.h"
#include "eval.h" #include "eval.h"
#include "hooks.h" #include "hooks.h"
#include "eval.h"
bool ipe_enabled; bool ipe_enabled;
static struct lsm_blob_sizes ipe_blobs __ro_after_init = { static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
.lbs_superblock = sizeof(struct ipe_superblock), .lbs_superblock = sizeof(struct ipe_superblock),
#ifdef CONFIG_IPE_PROP_DM_VERITY
.lbs_bdev = sizeof(struct ipe_bdev),
#endif /* CONFIG_IPE_PROP_DM_VERITY */
}; };
static const struct lsm_id ipe_lsmid = { static const struct lsm_id ipe_lsmid = {
...@@ -24,6 +28,13 @@ struct ipe_superblock *ipe_sb(const struct super_block *sb) ...@@ -24,6 +28,13 @@ struct ipe_superblock *ipe_sb(const struct super_block *sb)
return sb->s_security + ipe_blobs.lbs_superblock; return sb->s_security + ipe_blobs.lbs_superblock;
} }
#ifdef CONFIG_IPE_PROP_DM_VERITY
struct ipe_bdev *ipe_bdev(struct block_device *b)
{
return b->bd_security + ipe_blobs.lbs_bdev;
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
static struct security_hook_list ipe_hooks[] __ro_after_init = { static struct security_hook_list ipe_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security), LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security),
LSM_HOOK_INIT(mmap_file, ipe_mmap_file), LSM_HOOK_INIT(mmap_file, ipe_mmap_file),
...@@ -31,6 +42,10 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = { ...@@ -31,6 +42,10 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
LSM_HOOK_INIT(kernel_read_file, ipe_kernel_read_file), LSM_HOOK_INIT(kernel_read_file, ipe_kernel_read_file),
LSM_HOOK_INIT(kernel_load_data, ipe_kernel_load_data), LSM_HOOK_INIT(kernel_load_data, ipe_kernel_load_data),
LSM_HOOK_INIT(initramfs_populated, ipe_unpack_initramfs), LSM_HOOK_INIT(initramfs_populated, ipe_unpack_initramfs),
#ifdef CONFIG_IPE_PROP_DM_VERITY
LSM_HOOK_INIT(bdev_free_security, ipe_bdev_free_security),
LSM_HOOK_INIT(bdev_setintegrity, ipe_bdev_setintegrity),
#endif /* CONFIG_IPE_PROP_DM_VERITY */
}; };
/** /**
......
...@@ -16,4 +16,8 @@ struct ipe_superblock *ipe_sb(const struct super_block *sb); ...@@ -16,4 +16,8 @@ struct ipe_superblock *ipe_sb(const struct super_block *sb);
extern bool ipe_enabled; extern bool ipe_enabled;
#ifdef CONFIG_IPE_PROP_DM_VERITY
struct ipe_bdev *ipe_bdev(struct block_device *b);
#endif /* CONFIG_IPE_PROP_DM_VERITY */
#endif /* _IPE_H */ #endif /* _IPE_H */
...@@ -33,6 +33,9 @@ enum ipe_action_type { ...@@ -33,6 +33,9 @@ enum ipe_action_type {
enum ipe_prop_type { enum ipe_prop_type {
IPE_PROP_BOOT_VERIFIED_FALSE, IPE_PROP_BOOT_VERIFIED_FALSE,
IPE_PROP_BOOT_VERIFIED_TRUE, IPE_PROP_BOOT_VERIFIED_TRUE,
IPE_PROP_DMV_ROOTHASH,
IPE_PROP_DMV_SIG_FALSE,
IPE_PROP_DMV_SIG_TRUE,
__IPE_PROP_MAX __IPE_PROP_MAX
}; };
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "policy.h" #include "policy.h"
#include "policy_parser.h" #include "policy_parser.h"
#include "digest.h"
#define START_COMMENT '#' #define START_COMMENT '#'
#define IPE_POLICY_DELIM " \t" #define IPE_POLICY_DELIM " \t"
...@@ -221,6 +222,7 @@ static void free_rule(struct ipe_rule *r) ...@@ -221,6 +222,7 @@ static void free_rule(struct ipe_rule *r)
list_for_each_entry_safe(p, t, &r->props, next) { list_for_each_entry_safe(p, t, &r->props, next) {
list_del(&p->next); list_del(&p->next);
ipe_digest_free(p->value);
kfree(p); kfree(p);
} }
...@@ -273,6 +275,9 @@ static enum ipe_action_type parse_action(char *t) ...@@ -273,6 +275,9 @@ static enum ipe_action_type parse_action(char *t)
static const match_table_t property_tokens = { static const match_table_t property_tokens = {
{IPE_PROP_BOOT_VERIFIED_FALSE, "boot_verified=FALSE"}, {IPE_PROP_BOOT_VERIFIED_FALSE, "boot_verified=FALSE"},
{IPE_PROP_BOOT_VERIFIED_TRUE, "boot_verified=TRUE"}, {IPE_PROP_BOOT_VERIFIED_TRUE, "boot_verified=TRUE"},
{IPE_PROP_DMV_ROOTHASH, "dmverity_roothash=%s"},
{IPE_PROP_DMV_SIG_FALSE, "dmverity_signature=FALSE"},
{IPE_PROP_DMV_SIG_TRUE, "dmverity_signature=TRUE"},
{IPE_PROP_INVALID, NULL} {IPE_PROP_INVALID, NULL}
}; };
...@@ -295,6 +300,7 @@ static int parse_property(char *t, struct ipe_rule *r) ...@@ -295,6 +300,7 @@ static int parse_property(char *t, struct ipe_rule *r)
struct ipe_prop *p = NULL; struct ipe_prop *p = NULL;
int rc = 0; int rc = 0;
int token; int token;
char *dup = NULL;
p = kzalloc(sizeof(*p), GFP_KERNEL); p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) if (!p)
...@@ -303,8 +309,22 @@ static int parse_property(char *t, struct ipe_rule *r) ...@@ -303,8 +309,22 @@ static int parse_property(char *t, struct ipe_rule *r)
token = match_token(t, property_tokens, args); token = match_token(t, property_tokens, args);
switch (token) { switch (token) {
case IPE_PROP_DMV_ROOTHASH:
dup = match_strdup(&args[0]);
if (!dup) {
rc = -ENOMEM;
goto err;
}
p->value = ipe_digest_parse(dup);
if (IS_ERR(p->value)) {
rc = PTR_ERR(p->value);
goto err;
}
fallthrough;
case IPE_PROP_BOOT_VERIFIED_FALSE: case IPE_PROP_BOOT_VERIFIED_FALSE:
case IPE_PROP_BOOT_VERIFIED_TRUE: case IPE_PROP_BOOT_VERIFIED_TRUE:
case IPE_PROP_DMV_SIG_FALSE:
case IPE_PROP_DMV_SIG_TRUE:
p->type = token; p->type = token;
break; break;
default: default:
...@@ -315,10 +335,12 @@ static int parse_property(char *t, struct ipe_rule *r) ...@@ -315,10 +335,12 @@ static int parse_property(char *t, struct ipe_rule *r)
goto err; goto err;
list_add_tail(&p->next, &r->props); list_add_tail(&p->next, &r->props);
out:
kfree(dup);
return rc; return rc;
err: err:
kfree(p); kfree(p);
return rc; goto out;
} }
/** /**
......
...@@ -5739,17 +5739,18 @@ EXPORT_SYMBOL(security_bdev_free); ...@@ -5739,17 +5739,18 @@ EXPORT_SYMBOL(security_bdev_free);
* Please note that the new hook should be invoked every time the security * Please note that the new hook should be invoked every time the security
* information is updated to keep these data current. For example, in dm-verity, * information is updated to keep these data current. For example, in dm-verity,
* if the mapping table is reloaded and configured to use a different dm-verity * if the mapping table is reloaded and configured to use a different dm-verity
* target with a new roothash and signing information, the previously stored data * target with a new roothash and signing information, the previously stored
* in the LSM blob will become obsolete. It is crucial to re-invoke the hook to * data in the LSM blob will become obsolete. It is crucial to re-invoke the
* refresh these data and ensure they are up to date. This necessity arises from * hook to refresh these data and ensure they are up to date. This necessity
* the design of device-mapper, where a device-mapper device is first created, and * arises from the design of device-mapper, where a device-mapper device is
* then targets are subsequently loaded into it. These targets can be modified * first created, and then targets are subsequently loaded into it. These
* multiple times during the device's lifetime. Therefore, while the LSM blob is * targets can be modified multiple times during the device's lifetime.
* allocated during the creation of the block device, its actual contents are * Therefore, while the LSM blob is allocated during the creation of the block
* not initialized at this stage and can change substantially over time. This * device, its actual contents are not initialized at this stage and can change
* includes alterations from data that the LSMs 'trusts' to those they do not, * substantially over time. This includes alterations from data that the LSMs
* making it essential to handle these changes correctly. Failure to address * 'trusts' to those they do not, making it essential to handle these changes
* this dynamic aspect could potentially allow for bypassing LSM checks. * correctly. Failure to address this dynamic aspect could potentially allow
* for bypassing LSM checks.
* *
* Return: Returns 0 on success, negative values on failure. * Return: Returns 0 on success, negative values on failure.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment