// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. */ #include <linux/slab.h>#include <linux/audit.h>#include <linux/types.h>#include <crypto/sha2.h> #include "ipe.h"#include "eval.h"#include "hooks.h"#include "policy.h"#include "audit.h"#include "digest.h" #define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY") #define IPE_AUDIT_HASH_ALG "sha256" /* keep in sync with audit_policy() */ #define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\ "policy_digest=" IPE_AUDIT_HASH_ALG ":"#define AUDIT_POLICY_LOAD_NULL_FMT "policy_name=? policy_version=? "\ "policy_digest=?"#define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\ "old_active_pol_version=%hu.%hu.%hu "\ "old_policy_digest=" IPE_AUDIT_HASH_ALG ":"#define AUDIT_OLD_ACTIVE_POLICY_NULL_FMT "old_active_pol_name=? "\ "old_active_pol_version=? "\ "old_policy_digest=?"#define AUDIT_NEW_ACTIVE_POLICY_FMT "new_active_pol_name=\"%s\" "\ "new_active_pol_version=%hu.%hu.%hu "\ "new_policy_digest=" IPE_AUDIT_HASH_ALG ":" static const char *const audit_op_names[__IPE_OP_MAX + 1] = { "EXECUTE", "FIRMWARE", "KMODULE", "KEXEC_IMAGE", "KEXEC_INITRAMFS", "POLICY", "X509_CERT", "UNKNOWN",}; static const char *const audit_hook_names[__IPE_HOOK_MAX] = { "BPRM_CHECK", "BPRM_CREDS_FOR_EXEC", "MMAP", "MPROTECT", "KERNEL_READ", "KERNEL_LOAD",}; static const char *const audit_prop_names[__IPE_PROP_MAX] = { "boot_verified=FALSE", "boot_verified=TRUE", "dmverity_roothash=", "dmverity_signature=FALSE", "dmverity_signature=TRUE", "fsverity_digest=", "fsverity_signature=FALSE", "fsverity_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_fsv_digest() - audit the digest of a fsverity_digest property. * @ab: Supplies a pointer to the audit_buffer to append to. * @d: Supplies a pointer to the digest structure. */static void audit_fsv_digest(struct audit_buffer *ab, const void *d){ audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]); ipe_digest_audit(ab, d);} /** * audit_rule() - audit an IPE policy rule. * @ab: Supplies a pointer to the audit_buffer to append to. * @r: Supplies a pointer to the ipe_rule to approximate a string form for. */static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r){ const struct ipe_prop *ptr; audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]); list_for_each_entry(ptr, &r->props, next) { switch (ptr->type) { case IPE_PROP_DMV_ROOTHASH: audit_dmv_roothash(ab, ptr->value); break; case IPE_PROP_FSV_DIGEST: audit_fsv_digest(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));} /** * ipe_audit_match() - Audit a rule match in a policy evaluation. * @ctx: Supplies a pointer to the evaluation context that was used in the * evaluation. * @match_type: Supplies the scope of the match: rule, operation default, * global default. * @act: Supplies the IPE's evaluation decision, deny or allow. * @r: Supplies a pointer to the rule that was matched, if possible. */void ipe_audit_match(const struct ipe_eval_ctx *const ctx, enum ipe_match match_type, enum ipe_action_type act, const struct ipe_rule *const r){ const char *op = audit_op_names[ctx->op]; char comm[sizeof(current->comm)]; struct audit_buffer *ab; struct inode *inode; if (act != IPE_ACTION_DENY && !READ_ONCE(success_audit)) return; ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN, AUDIT_IPE_ACCESS); if (!ab) return; audit_log_format(ab, "ipe_op=%s ipe_hook=%s enforcing=%d pid=%d comm=", op, audit_hook_names[ctx->hook], READ_ONCE(enforce), task_tgid_nr(current)); audit_log_untrustedstring(ab, get_task_comm(comm, current)); if (ctx->file) { audit_log_d_path(ab, " path=", &ctx->file->f_path); inode = file_inode(ctx->file); if (inode) { audit_log_format(ab, " dev="); audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_format(ab, " ino=%llu", inode->i_ino); } else { audit_log_format(ab, " dev=? ino=?"); } } else { audit_log_format(ab, " path=? dev=? ino=?"); } if (match_type == IPE_MATCH_RULE) audit_rule(ab, r); else if (match_type == IPE_MATCH_TABLE) audit_log_format(ab, " rule=\"DEFAULT op=%s action=%s\"", op, ACTSTR(act)); else audit_log_format(ab, " rule=\"DEFAULT action=%s\"", ACTSTR(act)); audit_log_end(ab);} /** * audit_policy() - Audit a policy's name, version and thumbprint to @ab. * @ab: Supplies a pointer to the audit buffer to append to. * @audit_format: Supplies a pointer to the audit format string * @p: Supplies a pointer to the policy to audit. */static void audit_policy(struct audit_buffer *ab, const char *audit_format, const struct ipe_policy *const p){ u8 digest[SHA256_DIGEST_SIZE]; sha256(p->pkcs7, p->pkcs7len, digest); audit_log_format(ab, audit_format, p->parsed->name, p->parsed->version.major, p->parsed->version.minor, p->parsed->version.rev); audit_log_n_hex(ab, digest, sizeof(digest));} /** * ipe_audit_policy_activation() - Audit a policy being activated. * @op: Supplies a pointer to the previously activated policy to audit. * @np: Supplies a pointer to the newly activated policy to audit. */void ipe_audit_policy_activation(const struct ipe_policy *const op, const struct ipe_policy *const np){ struct audit_buffer *ab; ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_IPE_CONFIG_CHANGE); if (!ab) return; if (op) { audit_policy(ab, AUDIT_OLD_ACTIVE_POLICY_FMT, op); audit_log_format(ab, " "); } else { /* * old active policy can be NULL if there is no kernel * built-in policy */ audit_log_format(ab, AUDIT_OLD_ACTIVE_POLICY_NULL_FMT); audit_log_format(ab, " "); } audit_policy(ab, AUDIT_NEW_ACTIVE_POLICY_FMT, np); audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1", from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); audit_log_end(ab);} /** * ipe_audit_policy_load() - Audit a policy loading event. * @p: Supplies a pointer to the policy to audit or an error pointer. */void ipe_audit_policy_load(const struct ipe_policy *const p){ struct audit_buffer *ab; int err = 0; ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_IPE_POLICY_LOAD); if (!ab) return; if (!IS_ERR(p)) { audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p); } else { audit_log_format(ab, AUDIT_POLICY_LOAD_NULL_FMT); err = PTR_ERR(p); } audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=%d errno=%d", from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current), !err, err); audit_log_end(ab);} /** * ipe_audit_enforce() - Audit a change in IPE's enforcement state. * @new_enforce: The new value enforce to be set. * @old_enforce: The old value currently in enforce. */void ipe_audit_enforce(bool new_enforce, bool old_enforce){ struct audit_buffer *ab; ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS); if (!ab) return; audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u" " enabled=1 old-enabled=1 lsm=ipe res=1", new_enforce, old_enforce, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); audit_log_end(ab);}
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
*/
#include <linux/slab.h>
#include <linux/audit.h>
#include <linux/types.h>
#include <crypto/sha2.h>
#include "ipe.h"
#include "eval.h"
#include "hooks.h"
#include "policy.h"
#include "audit.h"
#include "digest.h"
#define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY")
#define IPE_AUDIT_HASH_ALG "sha256" /* keep in sync with audit_policy() */
#define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\
"policy_digest=" IPE_AUDIT_HASH_ALG ":"
#define AUDIT_POLICY_LOAD_NULL_FMT "policy_name=? policy_version=? "\
"policy_digest=?"
#define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\
"old_active_pol_version=%hu.%hu.%hu "\
"old_policy_digest=" IPE_AUDIT_HASH_ALG ":"
#define AUDIT_OLD_ACTIVE_POLICY_NULL_FMT "old_active_pol_name=? "\
"old_active_pol_version=? "\
"old_policy_digest=?"
#define AUDIT_NEW_ACTIVE_POLICY_FMT "new_active_pol_name=\"%s\" "\
"new_active_pol_version=%hu.%hu.%hu "\
"new_policy_digest=" IPE_AUDIT_HASH_ALG ":"
static const char *const audit_op_names[__IPE_OP_MAX + 1] = {
"EXECUTE",
"FIRMWARE",
"KMODULE",
"KEXEC_IMAGE",
"KEXEC_INITRAMFS",
"POLICY",
"X509_CERT",
"UNKNOWN",
};
static const char *const audit_hook_names[__IPE_HOOK_MAX] = {
"BPRM_CHECK",
"BPRM_CREDS_FOR_EXEC",
"MMAP",
"MPROTECT",
"KERNEL_READ",
"KERNEL_LOAD",
};
static const char *const audit_prop_names[__IPE_PROP_MAX] = {
"boot_verified=FALSE",
"boot_verified=TRUE",
"dmverity_roothash=",
"dmverity_signature=FALSE",
"dmverity_signature=TRUE",
"fsverity_digest=",
"fsverity_signature=FALSE",
"fsverity_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_fsv_digest() - audit the digest of a fsverity_digest property.
* @ab: Supplies a pointer to the audit_buffer to append to.
* @d: Supplies a pointer to the digest structure.
*/
static void audit_fsv_digest(struct audit_buffer *ab, const void *d)
{
audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]);
ipe_digest_audit(ab, d);
}
/**
* audit_rule() - audit an IPE policy rule.
* @ab: Supplies a pointer to the audit_buffer to append to.
* @r: Supplies a pointer to the ipe_rule to approximate a string form for.
*/
static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r)
{
const struct ipe_prop *ptr;
audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]);
list_for_each_entry(ptr, &r->props, next) {
switch (ptr->type) {
case IPE_PROP_DMV_ROOTHASH:
audit_dmv_roothash(ab, ptr->value);
break;
case IPE_PROP_FSV_DIGEST:
audit_fsv_digest(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));
}
/**
* ipe_audit_match() - Audit a rule match in a policy evaluation.
* @ctx: Supplies a pointer to the evaluation context that was used in the
* evaluation.
* @match_type: Supplies the scope of the match: rule, operation default,
* global default.
* @act: Supplies the IPE's evaluation decision, deny or allow.
* @r: Supplies a pointer to the rule that was matched, if possible.
*/
void ipe_audit_match(const struct ipe_eval_ctx *const ctx,
enum ipe_match match_type,
enum ipe_action_type act, const struct ipe_rule *const r)
{
const char *op = audit_op_names[ctx->op];
char comm[sizeof(current->comm)];
struct audit_buffer *ab;
struct inode *inode;
if (act != IPE_ACTION_DENY && !READ_ONCE(success_audit))
return;
ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN,
AUDIT_IPE_ACCESS);
if (!ab)
return;
audit_log_format(ab, "ipe_op=%s ipe_hook=%s enforcing=%d pid=%d comm=",
op, audit_hook_names[ctx->hook], READ_ONCE(enforce),
task_tgid_nr(current));
audit_log_untrustedstring(ab, get_task_comm(comm, current));
if (ctx->file) {
audit_log_d_path(ab, " path=", &ctx->file->f_path);
inode = file_inode(ctx->file);
if (inode) {
audit_log_format(ab, " dev=");
audit_log_untrustedstring(ab, inode->i_sb->s_id);
audit_log_format(ab, " ino=%llu", inode->i_ino);
} else {
audit_log_format(ab, " dev=? ino=?");
}
} else {
audit_log_format(ab, " path=? dev=? ino=?");
}
if (match_type == IPE_MATCH_RULE)
audit_rule(ab, r);
else if (match_type == IPE_MATCH_TABLE)
audit_log_format(ab, " rule=\"DEFAULT op=%s action=%s\"", op,
ACTSTR(act));
else
audit_log_format(ab, " rule=\"DEFAULT action=%s\"",
ACTSTR(act));
audit_log_end(ab);
}
/**
* audit_policy() - Audit a policy's name, version and thumbprint to @ab.
* @ab: Supplies a pointer to the audit buffer to append to.
* @audit_format: Supplies a pointer to the audit format string
* @p: Supplies a pointer to the policy to audit.
*/
static void audit_policy(struct audit_buffer *ab,
const char *audit_format,
const struct ipe_policy *const p)
{
u8 digest[SHA256_DIGEST_SIZE];
sha256(p->pkcs7, p->pkcs7len, digest);
audit_log_format(ab, audit_format, p->parsed->name,
p->parsed->version.major, p->parsed->version.minor,
p->parsed->version.rev);
audit_log_n_hex(ab, digest, sizeof(digest));
}
/**
* ipe_audit_policy_activation() - Audit a policy being activated.
* @op: Supplies a pointer to the previously activated policy to audit.
* @np: Supplies a pointer to the newly activated policy to audit.
*/
void ipe_audit_policy_activation(const struct ipe_policy *const op,
const struct ipe_policy *const np)
{
struct audit_buffer *ab;
ab = audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_IPE_CONFIG_CHANGE);
if (!ab)
return;
if (op) {
audit_policy(ab, AUDIT_OLD_ACTIVE_POLICY_FMT, op);
audit_log_format(ab, " ");
} else {
/*
* old active policy can be NULL if there is no kernel
* built-in policy
*/
audit_log_format(ab, AUDIT_OLD_ACTIVE_POLICY_NULL_FMT);
audit_log_format(ab, " ");
}
audit_policy(ab, AUDIT_NEW_ACTIVE_POLICY_FMT, np);
audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1",
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
audit_log_end(ab);
}
/**
* ipe_audit_policy_load() - Audit a policy loading event.
* @p: Supplies a pointer to the policy to audit or an error pointer.
*/
void ipe_audit_policy_load(const struct ipe_policy *const p)
{
struct audit_buffer *ab;
int err = 0;
ab = audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_IPE_POLICY_LOAD);
if (!ab)
return;
if (!IS_ERR(p)) {
audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
} else {
audit_log_format(ab, AUDIT_POLICY_LOAD_NULL_FMT);
err = PTR_ERR(p);
}
audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=%d errno=%d",
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current), !err, err);
audit_log_end(ab);
}
/**
* ipe_audit_enforce() - Audit a change in IPE's enforcement state.
* @new_enforce: The new value enforce to be set.
* @old_enforce: The old value currently in enforce.
*/
void ipe_audit_enforce(bool new_enforce, bool old_enforce)
{
struct audit_buffer *ab;
ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS);
if (!ab)
return;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u"
" enabled=1 old-enabled=1 lsm=ipe res=1",
new_enforce, old_enforce,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
audit_log_end(ab);
}