1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 */ 5 6 #include <linux/slab.h> 7 #include <linux/audit.h> 8 #include <linux/types.h> 9 #include <crypto/hash.h> 10 11 #include "ipe.h" 12 #include "eval.h" 13 #include "hooks.h" 14 #include "policy.h" 15 #include "audit.h" 16 #include "digest.h" 17 18 #define ACTSTR(x) ((x) == IPE_ACTION_ALLOW ? "ALLOW" : "DENY") 19 20 #define IPE_AUDIT_HASH_ALG "sha256" 21 22 #define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\ 23 "policy_digest=" IPE_AUDIT_HASH_ALG ":" 24 #define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\ 25 "old_active_pol_version=%hu.%hu.%hu "\ 26 "old_policy_digest=" IPE_AUDIT_HASH_ALG ":" 27 #define AUDIT_OLD_ACTIVE_POLICY_NULL_FMT "old_active_pol_name=? "\ 28 "old_active_pol_version=? "\ 29 "old_policy_digest=?" 30 #define AUDIT_NEW_ACTIVE_POLICY_FMT "new_active_pol_name=\"%s\" "\ 31 "new_active_pol_version=%hu.%hu.%hu "\ 32 "new_policy_digest=" IPE_AUDIT_HASH_ALG ":" 33 34 static const char *const audit_op_names[__IPE_OP_MAX + 1] = { 35 "EXECUTE", 36 "FIRMWARE", 37 "KMODULE", 38 "KEXEC_IMAGE", 39 "KEXEC_INITRAMFS", 40 "POLICY", 41 "X509_CERT", 42 "UNKNOWN", 43 }; 44 45 static const char *const audit_hook_names[__IPE_HOOK_MAX] = { 46 "BPRM_CHECK", 47 "MMAP", 48 "MPROTECT", 49 "KERNEL_READ", 50 "KERNEL_LOAD", 51 }; 52 53 static const char *const audit_prop_names[__IPE_PROP_MAX] = { 54 "boot_verified=FALSE", 55 "boot_verified=TRUE", 56 "dmverity_roothash=", 57 "dmverity_signature=FALSE", 58 "dmverity_signature=TRUE", 59 "fsverity_digest=", 60 "fsverity_signature=FALSE", 61 "fsverity_signature=TRUE", 62 }; 63 64 /** 65 * audit_dmv_roothash() - audit the roothash of a dmverity_roothash property. 66 * @ab: Supplies a pointer to the audit_buffer to append to. 67 * @rh: Supplies a pointer to the digest structure. 68 */ 69 static void audit_dmv_roothash(struct audit_buffer *ab, const void *rh) 70 { 71 audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_DMV_ROOTHASH]); 72 ipe_digest_audit(ab, rh); 73 } 74 75 /** 76 * audit_fsv_digest() - audit the digest of a fsverity_digest property. 77 * @ab: Supplies a pointer to the audit_buffer to append to. 78 * @d: Supplies a pointer to the digest structure. 79 */ 80 static void audit_fsv_digest(struct audit_buffer *ab, const void *d) 81 { 82 audit_log_format(ab, "%s", audit_prop_names[IPE_PROP_FSV_DIGEST]); 83 ipe_digest_audit(ab, d); 84 } 85 86 /** 87 * audit_rule() - audit an IPE policy rule. 88 * @ab: Supplies a pointer to the audit_buffer to append to. 89 * @r: Supplies a pointer to the ipe_rule to approximate a string form for. 90 */ 91 static void audit_rule(struct audit_buffer *ab, const struct ipe_rule *r) 92 { 93 const struct ipe_prop *ptr; 94 95 audit_log_format(ab, " rule=\"op=%s ", audit_op_names[r->op]); 96 97 list_for_each_entry(ptr, &r->props, next) { 98 switch (ptr->type) { 99 case IPE_PROP_DMV_ROOTHASH: 100 audit_dmv_roothash(ab, ptr->value); 101 break; 102 case IPE_PROP_FSV_DIGEST: 103 audit_fsv_digest(ab, ptr->value); 104 break; 105 default: 106 audit_log_format(ab, "%s", audit_prop_names[ptr->type]); 107 break; 108 } 109 110 audit_log_format(ab, " "); 111 } 112 113 audit_log_format(ab, "action=%s\"", ACTSTR(r->action)); 114 } 115 116 /** 117 * ipe_audit_match() - Audit a rule match in a policy evaluation. 118 * @ctx: Supplies a pointer to the evaluation context that was used in the 119 * evaluation. 120 * @match_type: Supplies the scope of the match: rule, operation default, 121 * global default. 122 * @act: Supplies the IPE's evaluation decision, deny or allow. 123 * @r: Supplies a pointer to the rule that was matched, if possible. 124 */ 125 void ipe_audit_match(const struct ipe_eval_ctx *const ctx, 126 enum ipe_match match_type, 127 enum ipe_action_type act, const struct ipe_rule *const r) 128 { 129 const char *op = audit_op_names[ctx->op]; 130 char comm[sizeof(current->comm)]; 131 struct audit_buffer *ab; 132 struct inode *inode; 133 134 if (act != IPE_ACTION_DENY && !READ_ONCE(success_audit)) 135 return; 136 137 ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN, 138 AUDIT_IPE_ACCESS); 139 if (!ab) 140 return; 141 142 audit_log_format(ab, "ipe_op=%s ipe_hook=%s enforcing=%d pid=%d comm=", 143 op, audit_hook_names[ctx->hook], READ_ONCE(enforce), 144 task_tgid_nr(current)); 145 audit_log_untrustedstring(ab, get_task_comm(comm, current)); 146 147 if (ctx->file) { 148 audit_log_d_path(ab, " path=", &ctx->file->f_path); 149 inode = file_inode(ctx->file); 150 if (inode) { 151 audit_log_format(ab, " dev="); 152 audit_log_untrustedstring(ab, inode->i_sb->s_id); 153 audit_log_format(ab, " ino=%lu", inode->i_ino); 154 } else { 155 audit_log_format(ab, " dev=? ino=?"); 156 } 157 } else { 158 audit_log_format(ab, " path=? dev=? ino=?"); 159 } 160 161 if (match_type == IPE_MATCH_RULE) 162 audit_rule(ab, r); 163 else if (match_type == IPE_MATCH_TABLE) 164 audit_log_format(ab, " rule=\"DEFAULT op=%s action=%s\"", op, 165 ACTSTR(act)); 166 else 167 audit_log_format(ab, " rule=\"DEFAULT action=%s\"", 168 ACTSTR(act)); 169 170 audit_log_end(ab); 171 } 172 173 /** 174 * audit_policy() - Audit a policy's name, version and thumbprint to @ab. 175 * @ab: Supplies a pointer to the audit buffer to append to. 176 * @audit_format: Supplies a pointer to the audit format string 177 * @p: Supplies a pointer to the policy to audit. 178 */ 179 static void audit_policy(struct audit_buffer *ab, 180 const char *audit_format, 181 const struct ipe_policy *const p) 182 { 183 SHASH_DESC_ON_STACK(desc, tfm); 184 struct crypto_shash *tfm; 185 u8 *digest = NULL; 186 187 tfm = crypto_alloc_shash(IPE_AUDIT_HASH_ALG, 0, 0); 188 if (IS_ERR(tfm)) 189 return; 190 191 desc->tfm = tfm; 192 193 digest = kzalloc(crypto_shash_digestsize(tfm), GFP_KERNEL); 194 if (!digest) 195 goto out; 196 197 if (crypto_shash_init(desc)) 198 goto out; 199 200 if (crypto_shash_update(desc, p->pkcs7, p->pkcs7len)) 201 goto out; 202 203 if (crypto_shash_final(desc, digest)) 204 goto out; 205 206 audit_log_format(ab, audit_format, p->parsed->name, 207 p->parsed->version.major, p->parsed->version.minor, 208 p->parsed->version.rev); 209 audit_log_n_hex(ab, digest, crypto_shash_digestsize(tfm)); 210 211 out: 212 kfree(digest); 213 crypto_free_shash(tfm); 214 } 215 216 /** 217 * ipe_audit_policy_activation() - Audit a policy being activated. 218 * @op: Supplies a pointer to the previously activated policy to audit. 219 * @np: Supplies a pointer to the newly activated policy to audit. 220 */ 221 void ipe_audit_policy_activation(const struct ipe_policy *const op, 222 const struct ipe_policy *const np) 223 { 224 struct audit_buffer *ab; 225 226 ab = audit_log_start(audit_context(), GFP_KERNEL, 227 AUDIT_IPE_CONFIG_CHANGE); 228 if (!ab) 229 return; 230 231 if (op) { 232 audit_policy(ab, AUDIT_OLD_ACTIVE_POLICY_FMT, op); 233 audit_log_format(ab, " "); 234 } else { 235 /* 236 * old active policy can be NULL if there is no kernel 237 * built-in policy 238 */ 239 audit_log_format(ab, AUDIT_OLD_ACTIVE_POLICY_NULL_FMT); 240 audit_log_format(ab, " "); 241 } 242 audit_policy(ab, AUDIT_NEW_ACTIVE_POLICY_FMT, np); 243 audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1", 244 from_kuid(&init_user_ns, audit_get_loginuid(current)), 245 audit_get_sessionid(current)); 246 247 audit_log_end(ab); 248 } 249 250 /** 251 * ipe_audit_policy_load() - Audit a policy being loaded into the kernel. 252 * @p: Supplies a pointer to the policy to audit. 253 */ 254 void ipe_audit_policy_load(const struct ipe_policy *const p) 255 { 256 struct audit_buffer *ab; 257 258 ab = audit_log_start(audit_context(), GFP_KERNEL, 259 AUDIT_IPE_POLICY_LOAD); 260 if (!ab) 261 return; 262 263 audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p); 264 audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1", 265 from_kuid(&init_user_ns, audit_get_loginuid(current)), 266 audit_get_sessionid(current)); 267 268 audit_log_end(ab); 269 } 270 271 /** 272 * ipe_audit_enforce() - Audit a change in IPE's enforcement state. 273 * @new_enforce: The new value enforce to be set. 274 * @old_enforce: The old value currently in enforce. 275 */ 276 void ipe_audit_enforce(bool new_enforce, bool old_enforce) 277 { 278 struct audit_buffer *ab; 279 280 ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS); 281 if (!ab) 282 return; 283 284 audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS, 285 "enforcing=%d old_enforcing=%d auid=%u ses=%u" 286 " enabled=1 old-enabled=1 lsm=ipe res=1", 287 new_enforce, old_enforce, 288 from_kuid(&init_user_ns, audit_get_loginuid(current)), 289 audit_get_sessionid(current)); 290 291 audit_log_end(ab); 292 } 293
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.