105a35163SDeven Bowers // SPDX-License-Identifier: GPL-2.0 205a35163SDeven Bowers /* 305a35163SDeven Bowers * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 405a35163SDeven Bowers */ 505a35163SDeven Bowers 605a35163SDeven Bowers #include <linux/fs.h> 705a35163SDeven Bowers #include <linux/types.h> 805a35163SDeven Bowers #include <linux/slab.h> 905a35163SDeven Bowers #include <linux/file.h> 1005a35163SDeven Bowers #include <linux/sched.h> 1105a35163SDeven Bowers #include <linux/rcupdate.h> 12f44554b5SDeven Bowers #include <linux/moduleparam.h> 1305a35163SDeven Bowers 1405a35163SDeven Bowers #include "ipe.h" 1505a35163SDeven Bowers #include "eval.h" 1605a35163SDeven Bowers #include "policy.h" 17f44554b5SDeven Bowers #include "audit.h" 18*e155858dSDeven Bowers #include "digest.h" 1905a35163SDeven Bowers 2005a35163SDeven Bowers struct ipe_policy __rcu *ipe_active_policy; 21f44554b5SDeven Bowers bool success_audit; 22a68916eaSDeven Bowers bool enforce = true; 23*e155858dSDeven Bowers #define INO_BLOCK_DEV(ino) ((ino)->i_sb->s_bdev) 2405a35163SDeven Bowers 25a8a74df1SFan Wu #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) 26a8a74df1SFan Wu 27a8a74df1SFan Wu /** 28a8a74df1SFan Wu * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context. 29a8a74df1SFan Wu * @ctx: Supplies a pointer to the context to be populated. 30a8a74df1SFan Wu * @file: Supplies the file struct of the file triggered IPE event. 31a8a74df1SFan Wu */ 32a8a74df1SFan Wu static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file) 33a8a74df1SFan Wu { 34a8a74df1SFan Wu ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs; 35a8a74df1SFan Wu } 36a8a74df1SFan Wu 37*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY 38*e155858dSDeven Bowers /** 39*e155858dSDeven Bowers * build_ipe_bdev_ctx() - Build ipe_bdev field of an evaluation context. 40*e155858dSDeven Bowers * @ctx: Supplies a pointer to the context to be populated. 41*e155858dSDeven Bowers * @ino: Supplies the inode struct of the file triggered IPE event. 42*e155858dSDeven Bowers */ 43*e155858dSDeven Bowers static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 44*e155858dSDeven Bowers { 45*e155858dSDeven Bowers if (INO_BLOCK_DEV(ino)) 46*e155858dSDeven Bowers ctx->ipe_bdev = ipe_bdev(INO_BLOCK_DEV(ino)); 47*e155858dSDeven Bowers } 48*e155858dSDeven Bowers #else 49*e155858dSDeven Bowers static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino) 50*e155858dSDeven Bowers { 51*e155858dSDeven Bowers } 52*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY */ 53*e155858dSDeven Bowers 5405a35163SDeven Bowers /** 5552443cb6SDeven Bowers * ipe_build_eval_ctx() - Build an ipe evaluation context. 5652443cb6SDeven Bowers * @ctx: Supplies a pointer to the context to be populated. 5752443cb6SDeven Bowers * @file: Supplies a pointer to the file to associated with the evaluation. 5852443cb6SDeven Bowers * @op: Supplies the IPE policy operation associated with the evaluation. 59f44554b5SDeven Bowers * @hook: Supplies the LSM hook associated with the evaluation. 6052443cb6SDeven Bowers */ 6152443cb6SDeven Bowers void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx, 6252443cb6SDeven Bowers const struct file *file, 63f44554b5SDeven Bowers enum ipe_op_type op, 64f44554b5SDeven Bowers enum ipe_hook_type hook) 6552443cb6SDeven Bowers { 6652443cb6SDeven Bowers ctx->file = file; 6752443cb6SDeven Bowers ctx->op = op; 68f44554b5SDeven Bowers ctx->hook = hook; 69a8a74df1SFan Wu 70*e155858dSDeven Bowers if (file) { 71a8a74df1SFan Wu build_ipe_sb_ctx(ctx, file); 72*e155858dSDeven Bowers build_ipe_bdev_ctx(ctx, d_real_inode(file->f_path.dentry)); 73*e155858dSDeven Bowers } 74a8a74df1SFan Wu } 75a8a74df1SFan Wu 76a8a74df1SFan Wu /** 77a8a74df1SFan Wu * evaluate_boot_verified() - Evaluate @ctx for the boot verified property. 78a8a74df1SFan Wu * @ctx: Supplies a pointer to the context being evaluated. 79a8a74df1SFan Wu * 80a8a74df1SFan Wu * Return: 81a8a74df1SFan Wu * * %true - The current @ctx match the @p 82a8a74df1SFan Wu * * %false - The current @ctx doesn't match the @p 83a8a74df1SFan Wu */ 84a8a74df1SFan Wu static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx) 85a8a74df1SFan Wu { 86a8a74df1SFan Wu return ctx->initramfs; 8752443cb6SDeven Bowers } 8852443cb6SDeven Bowers 89*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY 90*e155858dSDeven Bowers /** 91*e155858dSDeven Bowers * evaluate_dmv_roothash() - Evaluate @ctx against a dmv roothash property. 92*e155858dSDeven Bowers * @ctx: Supplies a pointer to the context being evaluated. 93*e155858dSDeven Bowers * @p: Supplies a pointer to the property being evaluated. 94*e155858dSDeven Bowers * 95*e155858dSDeven Bowers * Return: 96*e155858dSDeven Bowers * * %true - The current @ctx match the @p 97*e155858dSDeven Bowers * * %false - The current @ctx doesn't match the @p 98*e155858dSDeven Bowers */ 99*e155858dSDeven Bowers static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx, 100*e155858dSDeven Bowers struct ipe_prop *p) 101*e155858dSDeven Bowers { 102*e155858dSDeven Bowers return !!ctx->ipe_bdev && 103*e155858dSDeven Bowers !!ctx->ipe_bdev->root_hash && 104*e155858dSDeven Bowers ipe_digest_eval(p->value, 105*e155858dSDeven Bowers ctx->ipe_bdev->root_hash); 106*e155858dSDeven Bowers } 107*e155858dSDeven Bowers #else 108*e155858dSDeven Bowers static bool evaluate_dmv_roothash(const struct ipe_eval_ctx *const ctx, 109*e155858dSDeven Bowers struct ipe_prop *p) 110*e155858dSDeven Bowers { 111*e155858dSDeven Bowers return false; 112*e155858dSDeven Bowers } 113*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY */ 114*e155858dSDeven Bowers 115*e155858dSDeven Bowers #ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE 116*e155858dSDeven Bowers /** 117*e155858dSDeven Bowers * evaluate_dmv_sig_false() - Evaluate @ctx against a dmv sig false property. 118*e155858dSDeven Bowers * @ctx: Supplies a pointer to the context being evaluated. 119*e155858dSDeven Bowers * 120*e155858dSDeven Bowers * Return: 121*e155858dSDeven Bowers * * %true - The current @ctx match the property 122*e155858dSDeven Bowers * * %false - The current @ctx doesn't match the property 123*e155858dSDeven Bowers */ 124*e155858dSDeven Bowers static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 125*e155858dSDeven Bowers { 126*e155858dSDeven Bowers return !ctx->ipe_bdev || (!ctx->ipe_bdev->dm_verity_signed); 127*e155858dSDeven Bowers } 128*e155858dSDeven Bowers 129*e155858dSDeven Bowers /** 130*e155858dSDeven Bowers * evaluate_dmv_sig_true() - Evaluate @ctx against a dmv sig true property. 131*e155858dSDeven Bowers * @ctx: Supplies a pointer to the context being evaluated. 132*e155858dSDeven Bowers * 133*e155858dSDeven Bowers * Return: 134*e155858dSDeven Bowers * * %true - The current @ctx match the property 135*e155858dSDeven Bowers * * %false - The current @ctx doesn't match the property 136*e155858dSDeven Bowers */ 137*e155858dSDeven Bowers static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 138*e155858dSDeven Bowers { 139*e155858dSDeven Bowers return !evaluate_dmv_sig_false(ctx); 140*e155858dSDeven Bowers } 141*e155858dSDeven Bowers #else 142*e155858dSDeven Bowers static bool evaluate_dmv_sig_false(const struct ipe_eval_ctx *const ctx) 143*e155858dSDeven Bowers { 144*e155858dSDeven Bowers return false; 145*e155858dSDeven Bowers } 146*e155858dSDeven Bowers 147*e155858dSDeven Bowers static bool evaluate_dmv_sig_true(const struct ipe_eval_ctx *const ctx) 148*e155858dSDeven Bowers { 149*e155858dSDeven Bowers return false; 150*e155858dSDeven Bowers } 151*e155858dSDeven Bowers #endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */ 152*e155858dSDeven Bowers 15352443cb6SDeven Bowers /** 15405a35163SDeven Bowers * evaluate_property() - Analyze @ctx against a rule property. 15505a35163SDeven Bowers * @ctx: Supplies a pointer to the context to be evaluated. 15605a35163SDeven Bowers * @p: Supplies a pointer to the property to be evaluated. 15705a35163SDeven Bowers * 158a8a74df1SFan Wu * This function Determines whether the specified @ctx 159a8a74df1SFan Wu * matches the conditions defined by a rule property @p. 16005a35163SDeven Bowers * 16105a35163SDeven Bowers * Return: 16205a35163SDeven Bowers * * %true - The current @ctx match the @p 16305a35163SDeven Bowers * * %false - The current @ctx doesn't match the @p 16405a35163SDeven Bowers */ 16505a35163SDeven Bowers static bool evaluate_property(const struct ipe_eval_ctx *const ctx, 16605a35163SDeven Bowers struct ipe_prop *p) 16705a35163SDeven Bowers { 168a8a74df1SFan Wu switch (p->type) { 169a8a74df1SFan Wu case IPE_PROP_BOOT_VERIFIED_FALSE: 170a8a74df1SFan Wu return !evaluate_boot_verified(ctx); 171a8a74df1SFan Wu case IPE_PROP_BOOT_VERIFIED_TRUE: 172a8a74df1SFan Wu return evaluate_boot_verified(ctx); 173*e155858dSDeven Bowers case IPE_PROP_DMV_ROOTHASH: 174*e155858dSDeven Bowers return evaluate_dmv_roothash(ctx, p); 175*e155858dSDeven Bowers case IPE_PROP_DMV_SIG_FALSE: 176*e155858dSDeven Bowers return evaluate_dmv_sig_false(ctx); 177*e155858dSDeven Bowers case IPE_PROP_DMV_SIG_TRUE: 178*e155858dSDeven Bowers return evaluate_dmv_sig_true(ctx); 179a8a74df1SFan Wu default: 18005a35163SDeven Bowers return false; 18105a35163SDeven Bowers } 182a8a74df1SFan Wu } 18305a35163SDeven Bowers 18405a35163SDeven Bowers /** 18505a35163SDeven Bowers * ipe_evaluate_event() - Analyze @ctx against the current active policy. 18605a35163SDeven Bowers * @ctx: Supplies a pointer to the context to be evaluated. 18705a35163SDeven Bowers * 18805a35163SDeven Bowers * This is the loop where all policy evaluations happen against the IPE policy. 18905a35163SDeven Bowers * 19005a35163SDeven Bowers * Return: 19105a35163SDeven Bowers * * %0 - Success 19205a35163SDeven Bowers * * %-EACCES - @ctx did not pass evaluation 19305a35163SDeven Bowers */ 19405a35163SDeven Bowers int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx) 19505a35163SDeven Bowers { 19605a35163SDeven Bowers const struct ipe_op_table *rules = NULL; 19705a35163SDeven Bowers const struct ipe_rule *rule = NULL; 19805a35163SDeven Bowers struct ipe_policy *pol = NULL; 19905a35163SDeven Bowers struct ipe_prop *prop = NULL; 20005a35163SDeven Bowers enum ipe_action_type action; 201f44554b5SDeven Bowers enum ipe_match match_type; 20205a35163SDeven Bowers bool match = false; 203a68916eaSDeven Bowers int rc = 0; 20405a35163SDeven Bowers 20505a35163SDeven Bowers rcu_read_lock(); 20605a35163SDeven Bowers 20705a35163SDeven Bowers pol = rcu_dereference(ipe_active_policy); 20805a35163SDeven Bowers if (!pol) { 20905a35163SDeven Bowers rcu_read_unlock(); 21005a35163SDeven Bowers return 0; 21105a35163SDeven Bowers } 21205a35163SDeven Bowers 21305a35163SDeven Bowers if (ctx->op == IPE_OP_INVALID) { 214f44554b5SDeven Bowers if (pol->parsed->global_default_action == IPE_ACTION_INVALID) { 21505a35163SDeven Bowers WARN(1, "no default rule set for unknown op, ALLOW it"); 216f44554b5SDeven Bowers action = IPE_ACTION_ALLOW; 217f44554b5SDeven Bowers } else { 218f44554b5SDeven Bowers action = pol->parsed->global_default_action; 219f44554b5SDeven Bowers } 220f44554b5SDeven Bowers match_type = IPE_MATCH_GLOBAL; 221f44554b5SDeven Bowers goto eval; 22205a35163SDeven Bowers } 22305a35163SDeven Bowers 22405a35163SDeven Bowers rules = &pol->parsed->rules[ctx->op]; 22505a35163SDeven Bowers 22605a35163SDeven Bowers list_for_each_entry(rule, &rules->rules, next) { 22705a35163SDeven Bowers match = true; 22805a35163SDeven Bowers 22905a35163SDeven Bowers list_for_each_entry(prop, &rule->props, next) { 23005a35163SDeven Bowers match = evaluate_property(ctx, prop); 23105a35163SDeven Bowers if (!match) 23205a35163SDeven Bowers break; 23305a35163SDeven Bowers } 23405a35163SDeven Bowers 23505a35163SDeven Bowers if (match) 23605a35163SDeven Bowers break; 23705a35163SDeven Bowers } 23805a35163SDeven Bowers 239f44554b5SDeven Bowers if (match) { 24005a35163SDeven Bowers action = rule->action; 241f44554b5SDeven Bowers match_type = IPE_MATCH_RULE; 242f44554b5SDeven Bowers } else if (rules->default_action != IPE_ACTION_INVALID) { 24305a35163SDeven Bowers action = rules->default_action; 244f44554b5SDeven Bowers match_type = IPE_MATCH_TABLE; 245f44554b5SDeven Bowers } else { 24605a35163SDeven Bowers action = pol->parsed->global_default_action; 247f44554b5SDeven Bowers match_type = IPE_MATCH_GLOBAL; 248f44554b5SDeven Bowers } 24905a35163SDeven Bowers 250f44554b5SDeven Bowers eval: 251f44554b5SDeven Bowers ipe_audit_match(ctx, match_type, action, rule); 25205a35163SDeven Bowers rcu_read_unlock(); 253f44554b5SDeven Bowers 25405a35163SDeven Bowers if (action == IPE_ACTION_DENY) 255a68916eaSDeven Bowers rc = -EACCES; 25605a35163SDeven Bowers 257a68916eaSDeven Bowers if (!READ_ONCE(enforce)) 258a68916eaSDeven Bowers rc = 0; 259a68916eaSDeven Bowers 260a68916eaSDeven Bowers return rc; 26105a35163SDeven Bowers } 262f44554b5SDeven Bowers 263f44554b5SDeven Bowers /* Set the right module name */ 264f44554b5SDeven Bowers #ifdef KBUILD_MODNAME 265f44554b5SDeven Bowers #undef KBUILD_MODNAME 266f44554b5SDeven Bowers #define KBUILD_MODNAME "ipe" 267f44554b5SDeven Bowers #endif 268f44554b5SDeven Bowers 269f44554b5SDeven Bowers module_param(success_audit, bool, 0400); 270f44554b5SDeven Bowers MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled"); 271a68916eaSDeven Bowers module_param(enforce, bool, 0400); 272a68916eaSDeven Bowers MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode"); 273