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

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
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#

obj-$(CONFIG_SECURITY_IPE) += \
	digest.o \
	eval.o \
	hooks.o \
	fs.o \
+27 −2
Original line number Diff line number Diff line
@@ -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)
	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));
}

security/ipe/digest.c

0 → 100644
+118 −0
Original line number Diff line number Diff line
// 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);
}

security/ipe/digest.h

0 → 100644
+26 −0
Original line number Diff line number Diff line
/* 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 */
Loading