1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
// 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/hash.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"
#define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\
"policy_digest=" IPE_AUDIT_HASH_ALG ":"
#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",
"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=%lu", 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)
{
SHASH_DESC_ON_STACK(desc, tfm);
struct crypto_shash *tfm;
u8 *digest = NULL;
tfm = crypto_alloc_shash(IPE_AUDIT_HASH_ALG, 0, 0);
if (IS_ERR(tfm))
return;
desc->tfm = tfm;
digest = kzalloc(crypto_shash_digestsize(tfm), GFP_KERNEL);
if (!digest)
goto out;
if (crypto_shash_init(desc))
goto out;
if (crypto_shash_update(desc, p->pkcs7, p->pkcs7len))
goto out;
if (crypto_shash_final(desc, digest))
goto out;
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, crypto_shash_digestsize(tfm));
out:
kfree(digest);
crypto_free_shash(tfm);
}
/**
* 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 being loaded into the kernel.
* @p: Supplies a pointer to the policy to audit.
*/
void ipe_audit_policy_load(const struct ipe_policy *const p)
{
struct audit_buffer *ab;
ab = audit_log_start(audit_context(), GFP_KERNEL,
AUDIT_IPE_POLICY_LOAD);
if (!ab)
return;
audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
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_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);
}
|