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 return !!ctx->ipe_bdev && 138 !!ctx->ipe_bdev->root_hash && 139 ipe_digest_eval(p->value, 140 ctx->ipe_bdev->root_hash); 141 } 142 #else 143 static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx, 144 struct ipe_prop *p) 145 { 146 return false; 147 } 148 #endif /* CONFIG_IPE_PROP_DM_VERITY */ 149 150 #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE 151 /** 152 * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property. 153 * @ctx: Supplies a pointer to the context being evaluated. 154 * 155 * Return: 156 * * %true - The current @ctx match the property 157 * * %false - The current @ctx doesn't match the property 158 */ 159 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 160 { 161 return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed); 162 } 163 164 /** 165 * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property. 166 * @ctx: Supplies a pointer to the context being evaluated. 167 * 168 * Return: 169 * * %true - The current @ctx match the property 170 * * %false - The current @ctx doesn't match the property 171 */ 172 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 173 { 174 return !evaluate_dmv_sig_false(ctx); 175 } 176 #else 177 static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 178 { 179 return false; 180 } 181 182 static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 183 { 184 return false; 185 } 186 #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 187 188 #ifdef CONFIG_IPE_PROP_FS_VERITY 189 /** 190 * evaluate_fsv_digest() - Evaluate @ctx against a fsv digest property. 191 * @ctx: Supplies a pointer to the context being evaluated. 192 * @p: Supplies a pointer to the property being evaluated. 193 * 194 * Return: 195 * * %true - The current @ctx match the @p 196 * * %false - The current @ctx doesn't match the @p 197 */ 198 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 199 struct ipe_prop *p) 200 { 201 enum hash_algo alg; 202 u8 digest[FS_VERITY_MAX_DIGEST_SIZE]; 203 struct digest_info info; 204 205 if (!ctx->ino) 206 return false; 207 if (!fsverity_get_digest((struct inode *)ctx->ino, 208 digest, 209 NULL, 210 &alg)) 211 return false; 212 213 info.alg = hash_algo_name[alg]; 214 info.digest = digest; 215 info.digest_len = hash_digest_size[alg]; 216 217 return ipe_digest_eval(p->value, &info); 218 } 219 #else 220 static bool evaluate_fsv_digest(const struct ipe_eval_ctx *const ctx, 221 struct ipe_prop *p) 222 { 223 return false; 224 } 225 #endif /* CONFIG_IPE_PROP_FS_VERITY */ 226 227 #ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG 228 /** 229 * evaluate_fsv_sig_false() - Evaluate @ctx against a fsv sig false property. 230 * @ctx: Supplies a pointer to the context being evaluated. 231 * 232 * Return: 233 * * %true - The current @ctx match the property 234 * * %false - The current @ctx doesn't match the property 235 */ 236 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 237 { 238 return !ctx->ino || 239 !IS_VERITY(ctx->ino) || 240 !ctx->ipe_inode || 241 !ctx->ipe_inode->fs_verity_signed; 242 } 243 244 /** 245 * evaluate_fsv_sig_true() - Evaluate @ctx against a fsv sig true property. 246 * @ctx: Supplies a pointer to the context being evaluated. 247 * 248 * Return: 249 * * %true - The current @ctx match the property 250 * * %false - The current @ctx doesn't match the property 251 */ 252 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 253 { 254 return !evaluate_fsv_sig_false(ctx); 255 } 256 #else 257 static bool evaluate_fsv_sig_false(const struct ipe_eval_ctx *const ctx) 258 { 259 return false; 260 } 261 262 static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx) 263 { 264 return false; 265 } 266 #endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */ 267 268 /** 269 * evaluate_property() - Analyze @ctx against a rule property. 270 * @ctx: Supplies a pointer to the context to be evaluated. 271 * @p: Supplies a pointer to the property to be evaluated. 272 * 273 * This function Determines whether the specified @ctx 274 * matches the conditions defined by a rule property @p. 275 * 276 * Return: 277 * * %true - The current @ctx match the @p 278 * * %false - The current @ctx doesn't match the @p 279 */ 280 static bool evaluate_property(const struct ipe_eval_ctx *const ctx, 281 struct ipe_prop *p) 282 { 283 switch (p->type) { 284 case IPE_PROP_BOOT_VERIFIED_FALSE: 285 return !evaluate_boot_verified(ctx); 286 case IPE_PROP_BOOT_VERIFIED_TRUE: 287 return evaluate_boot_verified(ctx); 288 case IPE_PROP_DMV_ROOTHASH: 289 return evaluate_dmv_roothash(ctx, p); 290 case IPE_PROP_DMV_SIG_FALSE: 291 return evaluate_dmv_sig_false(ctx); 292 case IPE_PROP_DMV_SIG_TRUE: 293 return evaluate_dmv_sig_true(ctx); 294 case IPE_PROP_FSV_DIGEST: 295 return evaluate_fsv_digest(ctx, p); 296 case IPE_PROP_FSV_SIG_FALSE: 297 return evaluate_fsv_sig_false(ctx); 298 case IPE_PROP_FSV_SIG_TRUE: 299 return evaluate_fsv_sig_true(ctx); 300 default: 301 return false; 302 } 303 } 304 305 /** 306 * ipe_evaluate_event() - Analyze @ctx against the current active policy. 307 * @ctx: Supplies a pointer to the context to be evaluated. 308 * 309 * This is the loop where all policy evaluations happen against the IPE policy. 310 * 311 * Return: 312 * * %0 - Success 313 * * %-EACCES - @ctx did not pass evaluation 314 */ 315 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx) 316 { 317 const struct ipe_op_table *rules = NULL; 318 const struct ipe_rule *rule = NULL; 319 struct ipe_policy *pol = NULL; 320 struct ipe_prop *prop = NULL; 321 enum ipe_action_type action; 322 enum ipe_match match_type; 323 bool match = false; 324 int rc = 0; 325 326 rcu_read_lock(); 327 328 pol = rcu_dereference(ipe_active_policy); 329 if (!pol) { 330 rcu_read_unlock(); 331 return 0; 332 } 333 334 if (ctx->op == IPE_OP_INVALID) { 335 if (pol->parsed->global_default_action == IPE_ACTION_INVALID) { 336 WARN(1, "no default rule set for unknown op, ALLOW it"); 337 action = IPE_ACTION_ALLOW; 338 } else { 339 action = pol->parsed->global_default_action; 340 } 341 match_type = IPE_MATCH_GLOBAL; 342 goto eval; 343 } 344 345 rules = &pol->parsed->rules[ctx->op]; 346 347 list_for_each_entry(rule, &rules->rules, next) { 348 match = true; 349 350 list_for_each_entry(prop, &rule->props, next) { 351 match = evaluate_property(ctx, prop); 352 if (!match) 353 break; 354 } 355 356 if (match) 357 break; 358 } 359 360 if (match) { 361 action = rule->action; 362 match_type = IPE_MATCH_RULE; 363 } else if (rules->default_action != IPE_ACTION_INVALID) { 364 action = rules->default_action; 365 match_type = IPE_MATCH_TABLE; 366 } else { 367 action = pol->parsed->global_default_action; 368 match_type = IPE_MATCH_GLOBAL; 369 } 370 371 eval: 372 ipe_audit_match(ctx, match_type, action, rule); 373 rcu_read_unlock(); 374 375 if (action == IPE_ACTION_DENY) 376 rc = -EACCES; 377 378 if (!READ_ONCE(enforce)) 379 rc = 0; 380 381 return rc; 382 } 383 384 /* Set the right module name */ 385 #ifdef KBUILD_MODNAME 386 #undef KBUILD_MODNAME 387 #define KBUILD_MODNAME "ipe" 388 #endif 389 390 module_param(success_audit, bool, 0400); 391 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled"); 392 module_param(enforce, bool, 0400); 393 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode"); 394
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.