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