1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 4 */ 5 6 #include <linux/fs.h> 7 #include <linux/types.h> 8 #include <linux/slab.h> 9 #include <linux/file.h> 10 #include <linux/sched.h> 11 #include <linux/rcupdate.h> 12 #include <linux/moduleparam.h> 13 #include <linux/fsverity.h> 14 15 #include "ipe.h" 16 #include "eval.h" 17 #include "policy.h" 18 #include "audit.h" 19 #include "digest.h" 20 21 struct ipe_policy __rcu *ipe_active_policy; 22 bool success_audit; 23 bool enforce = true; 24 #define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev) 25 26 #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) 27 28 /** 29 * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context. 30 * @ctx: Supplies a pointer to the context to be populated. 31 * @file: Supplies the file struct of the file triggered IPE event. 32 */ 33 static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file) 34 { 35 ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs; 36 } 37 38 #ifdef CONFIG_IPE_PROP_DM_VERITY 39 /** 40 * build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context. 41 * @ctx: Supplies a pointer to the context to be populated. 42 * @ino: Supplies the inode struct of the file triggered IPE event. 43 */ 44 static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 45 { 46 if (INO_BLOCK_DEV(ino)) 47 ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino)); 48 } 49 #else 50 static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 51 { 52 } 53 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 54 55 #ifdef CONFIG_IPE_PROP_FS_VERITY 56 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 57 static void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx, 58 const struct inode *const ino) 59 { 60 ctx->ipe_inode = ipe_inode(ctx->ino); 61 } 62 #else 63 static inline void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx, 64 const struct inode *const ino) 65 { 66 } 67 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 68 69 /** 70 * build_ipe_inode_ctx() - Build inode fields of an evaluation context. 71 * @ctx: Supplies a pointer to the context to be populated. 72 * @ino: Supplies the inode struct of the file triggered IPE event. 73 */ 74 static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 75 { 76 ctx->ino = ino; 77 build_ipe_inode_blob_ctx(ctx, ino); 78 } 79 #else 80 static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 81 { 82 } 83 #endif /* CONFIG_IPE_PROP_FS_VERITY */ 84 85 /** 86 * ipe_build_eval_ctx() - Build an ipe evaluation context. 87 * @ctx: Supplies a pointer to the context to be populated. 88 * @file: Supplies a pointer to the file to associated with the evaluation. 89 * @op: Supplies the IPE policy operation associated with the evaluation. 90 * @hook: Supplies the LSM hook associated with the evaluation. 91 */ 92 void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx, 93 const struct file *file, 94 enum ipe_op_type op, 95 enum ipe_hook_type hook) 96 { 97 struct inode *ino; 98 99 ctx->file = file; 100 ctx->op = op; 101 ctx->hook = hook; 102 103 if (file) { 104 build_ipe_sb_ctx(ctx, file); 105 ino = d_real_inode(file->f_path.dentry); 106 build_ipe_bdev_ctx(ctx, ino); 107 build_ipe_inode_ctx(ctx, ino); 108 } 109 } 110 111 /** 112 * evaluate_boot_verified() - Evaluate @ctx for the boot verified property. 113 * @ctx: Supplies a pointer to the context being evaluated. 114 * 115 * Return: 116 * * %true - The current @ctx match the @p 117 * * %false - The current @ctx doesn't match the @p 118 */ 119 static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx) 120 { 121 return ctx->initramfs; 122 } 123 124 #ifdef CONFIG_IPE_PROP_DM_VERITY 125 /** 126 * evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property. 127 * @ctx: Supplies a pointer to the context being evaluated. 128 * @p: Supplies a pointer to the property being evaluated. 129 * 130 * Return: 131 * * %true - The current @ctx match the @p 132 * * %false - The current @ctx doesn't match the @p 133 */ 134 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx, 135 struct ipe_prop *p) 136 { 137 const struct digest_info *root_hash; 138 139 if (!ctx->ipe_bdev) 140 return false; 141 142 root_hash = rcu_dereference(ctx->ipe_bdev->root_hash); 143 144 return root_hash && ipe_digest_eval(p->value, root_hash); 145 } 146 #else 147 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx, 148 struct ipe_prop *p) 149 { 150 return false; 151 } 152 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 153 154 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE 155 /** 156 * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property. 157 * @ctx: Supplies a pointer to the context being evaluated. 158 * 159 * Return: 160 * * %true - The current @ctx match the property 161 * * %false - The current @ctx doesn't match the property 162 */ 163 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 164 { 165 return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed); 166 } 167 168 /** 169 * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property. 170 * @ctx: Supplies a pointer to the context being evaluated. 171 * 172 * Return: 173 * * %true - The current @ctx match the property 174 * * %false - The current @ctx doesn't match the property 175 */ 176 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 177 { 178 return !evaluate_dmv_sig_false(ctx); 179 } 180 #else 181 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 182 { 183 return false; 184 } 185 186 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 187 { 188 return false; 189 } 190 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 191 192 #ifdef CONFIG_IPE_PROP_FS_VERITY 193 /** 194 * evaluate_fsv_digest() - Evaluate @ctx against a fsv digest property. 195 * @ctx: Supplies a pointer to the context being evaluated. 196 * @p: Supplies a pointer to the property being evaluated. 197 * 198 * Return: 199 * * %true - The current @ctx match the @p 200 * * %false - The current @ctx doesn't match the @p 201 */ 202 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 203 struct ipe_prop *p) 204 { 205 enum hash_algo alg; 206 u8 digest[FS_VERITY_MAX_DIGEST_SIZE]; 207 struct digest_info info; 208 209 if (!ctx->ino) 210 return false; 211 if (!fsverity_get_digest((struct inode *)ctx->ino, 212 digest, 213 NULL, 214 &alg)) 215 return false; 216 217 info.alg = hash_algo_name[alg]; 218 info.digest = digest; 219 info.digest_len = hash_digest_size[alg]; 220 221 return ipe_digest_eval(p->value, &info); 222 } 223 #else 224 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 225 struct ipe_prop *p) 226 { 227 return false; 228 } 229 #endif /* CONFIG_IPE_PROP_FS_VERITY */ 230 231 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 232 /** 233 * evaluate_fsv_sig_false() - Evaluate @ctx against a fsv sig false property. 234 * @ctx: Supplies a pointer to the context being evaluated. 235 * 236 * Return: 237 * * %true - The current @ctx match the property 238 * * %false - The current @ctx doesn't match the property 239 */ 240 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 241 { 242 return !ctx->ino || 243 !IS_VERITY(ctx->ino) || 244 !ctx->ipe_inode || 245 !ctx->ipe_inode->fs_verity_signed; 246 } 247 248 /** 249 * evaluate_fsv_sig_true() - Evaluate @ctx against a fsv sig true property. 250 * @ctx: Supplies a pointer to the context being evaluated. 251 * 252 * Return: 253 * * %true - The current @ctx match the property 254 * * %false - The current @ctx doesn't match the property 255 */ 256 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 257 { 258 return !evaluate_fsv_sig_false(ctx); 259 } 260 #else 261 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 262 { 263 return false; 264 } 265 266 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 267 { 268 return false; 269 } 270 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 271 272 /** 273 * evaluate_property() - Analyze @ctx against a rule property. 274 * @ctx: Supplies a pointer to the context to be evaluated. 275 * @p: Supplies a pointer to the property to be evaluated. 276 * 277 * This function Determines whether the specified @ctx 278 * matches the conditions defined by a rule property @p. 279 * 280 * Return: 281 * * %true - The current @ctx match the @p 282 * * %false - The current @ctx doesn't match the @p 283 */ 284 static bool evaluate_property(const struct ipe_eval_ctx *const ctx, 285 struct ipe_prop *p) 286 { 287 switch (p->type) { 288 case IPE_PROP_BOOT_VERIFIED_FALSE: 289 return !evaluate_boot_verified(ctx); 290 case IPE_PROP_BOOT_VERIFIED_TRUE: 291 return evaluate_boot_verified(ctx); 292 case IPE_PROP_DMV_ROOTHASH: 293 return evaluate_dmv_roothash(ctx, p); 294 case IPE_PROP_DMV_SIG_FALSE: 295 return evaluate_dmv_sig_false(ctx); 296 case IPE_PROP_DMV_SIG_TRUE: 297 return evaluate_dmv_sig_true(ctx); 298 case IPE_PROP_FSV_DIGEST: 299 return evaluate_fsv_digest(ctx, p); 300 case IPE_PROP_FSV_SIG_FALSE: 301 return evaluate_fsv_sig_false(ctx); 302 case IPE_PROP_FSV_SIG_TRUE: 303 return evaluate_fsv_sig_true(ctx); 304 default: 305 return false; 306 } 307 } 308 309 /** 310 * ipe_evaluate_event() - Analyze @ctx against the current active policy. 311 * @ctx: Supplies a pointer to the context to be evaluated. 312 * 313 * This is the loop where all policy evaluations happen against the IPE policy. 314 * 315 * Return: 316 * * %0 - Success 317 * * %-EACCES - @ctx did not pass evaluation 318 */ 319 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx) 320 { 321 const struct ipe_op_table *rules = NULL; 322 const struct ipe_rule *rule = NULL; 323 struct ipe_policy *pol = NULL; 324 struct ipe_prop *prop = NULL; 325 enum ipe_action_type action; 326 enum ipe_match match_type; 327 bool match = false; 328 int rc = 0; 329 330 rcu_read_lock(); 331 332 pol = rcu_dereference(ipe_active_policy); 333 if (!pol) { 334 rcu_read_unlock(); 335 return 0; 336 } 337 338 if (ctx->op == IPE_OP_INVALID) { 339 if (pol->parsed->global_default_action == IPE_ACTION_INVALID) { 340 WARN(1, "no default rule set for unknown op, ALLOW it"); 341 action = IPE_ACTION_ALLOW; 342 } else { 343 action = pol->parsed->global_default_action; 344 } 345 match_type = IPE_MATCH_GLOBAL; 346 goto eval; 347 } 348 349 rules = &pol->parsed->rules[ctx->op]; 350 351 list_for_each_entry(rule, &rules->rules, next) { 352 match = true; 353 354 list_for_each_entry(prop, &rule->props, next) { 355 match = evaluate_property(ctx, prop); 356 if (!match) 357 break; 358 } 359 360 if (match) 361 break; 362 } 363 364 if (match) { 365 action = rule->action; 366 match_type = IPE_MATCH_RULE; 367 } else if (rules->default_action != IPE_ACTION_INVALID) { 368 action = rules->default_action; 369 match_type = IPE_MATCH_TABLE; 370 } else { 371 action = pol->parsed->global_default_action; 372 match_type = IPE_MATCH_GLOBAL; 373 } 374 375 eval: 376 ipe_audit_match(ctx, match_type, action, rule); 377 rcu_read_unlock(); 378 379 if (action == IPE_ACTION_DENY) 380 rc = -EACCES; 381 382 if (!READ_ONCE(enforce)) 383 rc = 0; 384 385 return rc; 386 } 387 388 /* Set the right module name */ 389 #ifdef KBUILD_MODNAME 390 #undef KBUILD_MODNAME 391 #define KBUILD_MODNAME "ipe" 392 #endif 393 394 module_param(success_audit, bool, 0400); 395 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled"); 396 module_param(enforce, bool, 0400); 397 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode"); 398