mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00: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
|
||||
select PKCS7_MESSAGE_PARSER
|
||||
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
|
||||
This option enables the Integrity Policy Enforcement LSM
|
||||
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.
|
||||
|
||||
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) += \
|
||||
digest.o \
|
||||
eval.o \
|
||||
hooks.o \
|
||||
fs.o \
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "hooks.h"
|
||||
#include "policy.h"
|
||||
#include "audit.h"
|
||||
#include "digest.h"
|
||||
|
||||
#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] = {
|
||||
"boot_verified=FALSE",
|
||||
"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.
|
||||
* @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]);
|
||||
|
||||
list_for_each_entry(ptr, &r->props, next)
|
||||
audit_log_format(ab, "%s ", audit_prop_names[ptr->type]);
|
||||
list_for_each_entry(ptr, &r->props, next) {
|
||||
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));
|
||||
}
|
||||
|
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 "policy.h"
|
||||
#include "audit.h"
|
||||
#include "digest.h"
|
||||
|
||||
struct ipe_policy __rcu *ipe_active_policy;
|
||||
bool success_audit;
|
||||
bool enforce = true;
|
||||
#define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev)
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#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.
|
||||
* @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->hook = hook;
|
||||
|
||||
if (file)
|
||||
if (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;
|
||||
}
|
||||
|
||||
#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.
|
||||
* @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);
|
||||
case IPE_PROP_BOOT_VERIFIED_TRUE:
|
||||
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:
|
||||
return false;
|
||||
}
|
||||
|
@ -22,12 +22,24 @@ struct ipe_superblock {
|
||||
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 {
|
||||
enum ipe_op_type op;
|
||||
enum ipe_hook_type hook;
|
||||
|
||||
const struct file *file;
|
||||
bool initramfs;
|
||||
#ifdef CONFIG_IPE_PROP_DM_VERITY
|
||||
const struct ipe_bdev *ipe_bdev;
|
||||
#endif /* CONFIG_IPE_PROP_DM_VERITY */
|
||||
};
|
||||
|
||||
enum ipe_match {
|
||||
|
@ -8,10 +8,12 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/blk_types.h>
|
||||
|
||||
#include "ipe.h"
|
||||
#include "hooks.h"
|
||||
#include "eval.h"
|
||||
#include "digest.h"
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
#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/binfmts.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/blk_types.h>
|
||||
|
||||
enum ipe_hook_type {
|
||||
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);
|
||||
|
||||
#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 */
|
||||
|
@ -7,11 +7,15 @@
|
||||
#include "ipe.h"
|
||||
#include "eval.h"
|
||||
#include "hooks.h"
|
||||
#include "eval.h"
|
||||
|
||||
bool ipe_enabled;
|
||||
|
||||
static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
|
||||
.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 = {
|
||||
@ -24,6 +28,13 @@ struct ipe_superblock *ipe_sb(const struct super_block *sb)
|
||||
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 = {
|
||||
LSM_HOOK_INIT(bprm_check_security, ipe_bprm_check_security),
|
||||
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_load_data, ipe_kernel_load_data),
|
||||
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;
|
||||
|
||||
#ifdef CONFIG_IPE_PROP_DM_VERITY
|
||||
struct ipe_bdev *ipe_bdev(struct block_device *b);
|
||||
#endif /* CONFIG_IPE_PROP_DM_VERITY */
|
||||
|
||||
#endif /* _IPE_H */
|
||||
|
@ -33,6 +33,9 @@ enum ipe_action_type {
|
||||
enum ipe_prop_type {
|
||||
IPE_PROP_BOOT_VERIFIED_FALSE,
|
||||
IPE_PROP_BOOT_VERIFIED_TRUE,
|
||||
IPE_PROP_DMV_ROOTHASH,
|
||||
IPE_PROP_DMV_SIG_FALSE,
|
||||
IPE_PROP_DMV_SIG_TRUE,
|
||||
__IPE_PROP_MAX
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "policy.h"
|
||||
#include "policy_parser.h"
|
||||
#include "digest.h"
|
||||
|
||||
#define START_COMMENT '#'
|
||||
#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_del(&p->next);
|
||||
ipe_digest_free(p->value);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
@ -273,6 +275,9 @@ static enum ipe_action_type parse_action(char *t)
|
||||
static const match_table_t property_tokens = {
|
||||
{IPE_PROP_BOOT_VERIFIED_FALSE, "boot_verified=FALSE"},
|
||||
{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}
|
||||
};
|
||||
|
||||
@ -295,6 +300,7 @@ static int parse_property(char *t, struct ipe_rule *r)
|
||||
struct ipe_prop *p = NULL;
|
||||
int rc = 0;
|
||||
int token;
|
||||
char *dup = NULL;
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
@ -303,8 +309,22 @@ static int parse_property(char *t, struct ipe_rule *r)
|
||||
token = match_token(t, property_tokens, args);
|
||||
|
||||
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_TRUE:
|
||||
case IPE_PROP_DMV_SIG_FALSE:
|
||||
case IPE_PROP_DMV_SIG_TRUE:
|
||||
p->type = token;
|
||||
break;
|
||||
default:
|
||||
@ -315,10 +335,12 @@ static int parse_property(char *t, struct ipe_rule *r)
|
||||
goto err;
|
||||
list_add_tail(&p->next, &r->props);
|
||||
|
||||
out:
|
||||
kfree(dup);
|
||||
return rc;
|
||||
err:
|
||||
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
|
||||
* 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
|
||||
* target with a new roothash and signing information, the previously stored data
|
||||
* in the LSM blob will become obsolete. It is crucial to re-invoke the hook to
|
||||
* refresh these data and ensure they are up to date. This necessity arises from
|
||||
* the design of device-mapper, where a device-mapper device is first created, and
|
||||
* then targets are subsequently loaded into it. These targets can be modified
|
||||
* multiple times during the device's lifetime. Therefore, while the LSM blob is
|
||||
* allocated during the creation of the block device, its actual contents are
|
||||
* not initialized at this stage and can change substantially over time. This
|
||||
* includes alterations from data that the LSMs 'trusts' to those they do not,
|
||||
* making it essential to handle these changes correctly. Failure to address
|
||||
* this dynamic aspect could potentially allow for bypassing LSM checks.
|
||||
* target with a new roothash and signing information, the previously stored
|
||||
* data in the LSM blob will become obsolete. It is crucial to re-invoke the
|
||||
* hook to refresh these data and ensure they are up to date. This necessity
|
||||
* arises from the design of device-mapper, where a device-mapper device is
|
||||
* first created, and then targets are subsequently loaded into it. These
|
||||
* targets can be modified multiple times during the device's lifetime.
|
||||
* Therefore, while the LSM blob is allocated during the creation of the block
|
||||
* device, its actual contents are not initialized at this stage and can change
|
||||
* substantially over time. This includes alterations from data that the LSMs
|
||||
* 'trusts' to those they do not, making it essential to handle these changes
|
||||
* correctly. Failure to address this dynamic aspect could potentially allow
|
||||
* for bypassing LSM checks.
|
||||
*
|
||||
* Return: Returns 0 on success, negative values on failure.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user