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 14 #include "ipe.h" 15 #include "eval.h" 16 #include "policy.h" 17 #include "audit.h" 18 19 struct ipe_policy __rcu *ipe_active_policy; 20 bool success_audit; 21 bool enforce = true; 22 23 #define FILE_SUPERBLOCK(f) ((f)->f_path.mnt->mnt_sb) 24 25 /** 26 * build_ipe_sb_ctx() - Build initramfs field of an ipe evaluation context. 27 * @ctx: Supplies a pointer to the context to be populated. 28 * @file: Supplies the file struct of the file triggered IPE event. 29 */ 30 static void build_ipe_sb_ctx(struct ipe_eval_ctx *ctx, const struct file *const file) 31 { 32 ctx->initramfs = ipe_sb(FILE_SUPERBLOCK(file))->initramfs; 33 } 34 35 /** 36 * ipe_build_eval_ctx() - Build an ipe evaluation context. 37 * @ctx: Supplies a pointer to the context to be populated. 38 * @file: Supplies a pointer to the file to associated with the evaluation. 39 * @op: Supplies the IPE policy operation associated with the evaluation. 40 * @hook: Supplies the LSM hook associated with the evaluation. 41 */ 42 void ipe_build_eval_ctx(struct ipe_eval_ctx *ctx, 43 const struct file *file, 44 enum ipe_op_type op, 45 enum ipe_hook_type hook) 46 { 47 ctx->file = file; 48 ctx->op = op; 49 ctx->hook = hook; 50 51 if (file) 52 build_ipe_sb_ctx(ctx, file); 53 } 54 55 /** 56 * evaluate_boot_verified() - Evaluate @ctx for the boot verified property. 57 * @ctx: Supplies a pointer to the context being evaluated. 58 * 59 * Return: 60 * * %true - The current @ctx match the @p 61 * * %false - The current @ctx doesn't match the @p 62 */ 63 static bool evaluate_boot_verified(const struct ipe_eval_ctx *const ctx) 64 { 65 return ctx->initramfs; 66 } 67 68 /** 69 * evaluate_property() - Analyze @ctx against a rule property. 70 * @ctx: Supplies a pointer to the context to be evaluated. 71 * @p: Supplies a pointer to the property to be evaluated. 72 * 73 * This function Determines whether the specified @ctx 74 * matches the conditions defined by a rule property @p. 75 * 76 * Return: 77 * * %true - The current @ctx match the @p 78 * * %false - The current @ctx doesn't match the @p 79 */ 80 static bool evaluate_property(const struct ipe_eval_ctx *const ctx, 81 struct ipe_prop *p) 82 { 83 switch (p->type) { 84 case IPE_PROP_BOOT_VERIFIED_FALSE: 85 return !evaluate_boot_verified(ctx); 86 case IPE_PROP_BOOT_VERIFIED_TRUE: 87 return evaluate_boot_verified(ctx); 88 default: 89 return false; 90 } 91 } 92 93 /** 94 * ipe_evaluate_event() - Analyze @ctx against the current active policy. 95 * @ctx: Supplies a pointer to the context to be evaluated. 96 * 97 * This is the loop where all policy evaluations happen against the IPE policy. 98 * 99 * Return: 100 * * %0 - Success 101 * * %-EACCES - @ctx did not pass evaluation 102 */ 103 int ipe_evaluate_event(const struct ipe_eval_ctx *const ctx) 104 { 105 const struct ipe_op_table *rules = NULL; 106 const struct ipe_rule *rule = NULL; 107 struct ipe_policy *pol = NULL; 108 struct ipe_prop *prop = NULL; 109 enum ipe_action_type action; 110 enum ipe_match match_type; 111 bool match = false; 112 int rc = 0; 113 114 rcu_read_lock(); 115 116 pol = rcu_dereference(ipe_active_policy); 117 if (!pol) { 118 rcu_read_unlock(); 119 return 0; 120 } 121 122 if (ctx->op == IPE_OP_INVALID) { 123 if (pol->parsed->global_default_action == IPE_ACTION_INVALID) { 124 WARN(1, "no default rule set for unknown op, ALLOW it"); 125 action = IPE_ACTION_ALLOW; 126 } else { 127 action = pol->parsed->global_default_action; 128 } 129 match_type = IPE_MATCH_GLOBAL; 130 goto eval; 131 } 132 133 rules = &pol->parsed->rules[ctx->op]; 134 135 list_for_each_entry(rule, &rules->rules, next) { 136 match = true; 137 138 list_for_each_entry(prop, &rule->props, next) { 139 match = evaluate_property(ctx, prop); 140 if (!match) 141 break; 142 } 143 144 if (match) 145 break; 146 } 147 148 if (match) { 149 action = rule->action; 150 match_type = IPE_MATCH_RULE; 151 } else if (rules->default_action != IPE_ACTION_INVALID) { 152 action = rules->default_action; 153 match_type = IPE_MATCH_TABLE; 154 } else { 155 action = pol->parsed->global_default_action; 156 match_type = IPE_MATCH_GLOBAL; 157 } 158 159 eval: 160 ipe_audit_match(ctx, match_type, action, rule); 161 rcu_read_unlock(); 162 163 if (action == IPE_ACTION_DENY) 164 rc = -EACCES; 165 166 if (!READ_ONCE(enforce)) 167 rc = 0; 168 169 return rc; 170 } 171 172 /* Set the right module name */ 173 #ifdef KBUILD_MODNAME 174 #undef KBUILD_MODNAME 175 #define KBUILD_MODNAME "ipe" 176 #endif 177 178 module_param(success_audit, bool, 0400); 179 MODULE_PARM_DESC(success_audit, "Start IPE with success auditing enabled"); 180 module_param(enforce, bool, 0400); 181 MODULE_PARM_DESC(enforce, "Start IPE in enforce or permissive mode"); 182