mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
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 <deven.desai@linux.microsoft.com> Signed-off-by: Fan Wu <wufan@linux.microsoft.com> [PM: fixed some line length issues in the comments] Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
parent
a6af7bc3d7
commit
e155858dd9
|
@ -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
|
||||||
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 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
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 @@
|
||||||
#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] = {
|
||||||
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)
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
118
security/ipe/digest.c
Normal file
118
security/ipe/digest.c
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
// 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);
|
||||||
|
}
|
26
security/ipe/digest.h
Normal file
26
security/ipe/digest.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/* 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 @@
|
||||||
#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
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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 {
|
||||||
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 @@
|
||||||
#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)
|
||||||
{
|
{
|
||||||
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 @@
|
||||||
#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);
|
||||||
|
|
||||||
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 @@
|
||||||
#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)
|
||||||
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 = {
|
||||||
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);
|
||||||
|
|
||||||
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 {
|
||||||
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 @@
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user