1 // SPDX-License-Identifier: GPL-2.0 1 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporati 4 */ 5 6 #include <linux/errno.h> 7 #include <linux/verification.h> 8 9 #include "ipe.h" 10 #include "eval.h" 11 #include "fs.h" 12 #include "policy.h" 13 #include "policy_parser.h" 14 #include "audit.h" 15 16 /* lock for synchronizing writers across ipe p 17 DEFINE_MUTEX(ipe_policy_lock); 18 19 /** 20 * ver_to_u64() - Convert an internal ipe_poli 21 * @p: Policy to extract the version from. 22 * 23 * Bits (LSB is index 0): 24 * [48,32] -> Major 25 * [32,16] -> Minor 26 * [16, 0] -> Revision 27 * 28 * Return: u64 version of the embedded version 29 */ 30 static inline u64 ver_to_u64(const struct ipe_ 31 { 32 u64 r; 33 34 r = (((u64)p->parsed->version.major) < 35 | (((u64)p->parsed->version.minor) < 36 | ((u64)(p->parsed->version.rev)); 37 38 return r; 39 } 40 41 /** 42 * ipe_free_policy() - Deallocate a given IPE 43 * @p: Supplies the policy to free. 44 * 45 * Safe to call on IS_ERR/NULL. 46 */ 47 void ipe_free_policy(struct ipe_policy *p) 48 { 49 if (IS_ERR_OR_NULL(p)) 50 return; 51 52 ipe_del_policyfs_node(p); 53 ipe_free_parsed_policy(p->parsed); 54 /* 55 * p->text is allocated only when p->p 56 * otherwise it points to the plaintex 57 */ 58 if (!p->pkcs7) 59 kfree(p->text); 60 kfree(p->pkcs7); 61 kfree(p); 62 } 63 64 static int set_pkcs7_data(void *ctx, const voi 65 size_t asn1hdrlen __ 66 { 67 struct ipe_policy *p = ctx; 68 69 p->text = (const char *)data; 70 p->textlen = len; 71 72 return 0; 73 } 74 75 /** 76 * ipe_update_policy() - parse a new policy an 77 * @root: Supplies a pointer to the securityfs 78 * @text: Supplies a pointer to the plain text 79 * @textlen: Supplies the length of @text. 80 * @pkcs7: Supplies a pointer to a buffer cont 81 * @pkcs7len: Supplies the length of @pkcs7len 82 * 83 * @text/@textlen is mutually exclusive with @ 84 * ipe_new_policy. 85 * 86 * Context: Requires root->i_rwsem to be held. 87 * Return: %0 on success. If an error occurs, 88 * the -errno. 89 */ 90 int ipe_update_policy(struct inode *root, cons 91 const char *pkcs7, size_ 92 { 93 struct ipe_policy *old, *ap, *new = NU 94 int rc = 0; 95 96 old = (struct ipe_policy *)root->i_pri 97 if (!old) 98 return -ENOENT; 99 100 new = ipe_new_policy(text, textlen, pk 101 if (IS_ERR(new)) 102 return PTR_ERR(new); 103 104 if (strcmp(new->parsed->name, old->par 105 rc = -EINVAL; 106 goto err; 107 } 108 109 if (ver_to_u64(old) >= ver_to_u64(new) 110 rc = -ESTALE; 111 goto err; 112 } 113 114 root->i_private = new; 115 swap(new->policyfs, old->policyfs); 116 ipe_audit_policy_load(new); 117 118 mutex_lock(&ipe_policy_lock); 119 ap = rcu_dereference_protected(ipe_act 120 lockdep 121 if (old == ap) { 122 rcu_assign_pointer(ipe_active_ 123 mutex_unlock(&ipe_policy_lock) 124 ipe_audit_policy_activation(ol 125 } else { 126 mutex_unlock(&ipe_policy_lock) 127 } 128 synchronize_rcu(); 129 ipe_free_policy(old); 130 131 return 0; 132 err: 133 ipe_free_policy(new); 134 return rc; 135 } 136 137 /** 138 * ipe_new_policy() - Allocate and parse an ip 139 * 140 * @text: Supplies a pointer to the plain-text 141 * @textlen: Supplies the length of @text. 142 * @pkcs7: Supplies a pointer to a pkcs7-signe 143 * @pkcs7len: Supplies the length of @pkcs7. 144 * 145 * @text/@textlen Should be NULL/0 if @pkcs7/@ 146 * 147 * Return: 148 * * a pointer to the ipe_policy structure 149 * * %-EBADMSG 150 * * %-ENOMEM 151 * * %-ERANGE 152 * * %-EINVAL 153 */ 154 struct ipe_policy *ipe_new_policy(const char * 155 const char * 156 { 157 struct ipe_policy *new = NULL; 158 int rc = 0; 159 160 new = kzalloc(sizeof(*new), GFP_KERNEL 161 if (!new) 162 return ERR_PTR(-ENOMEM); 163 164 if (!text) { 165 new->pkcs7len = pkcs7len; 166 new->pkcs7 = kmemdup(pkcs7, pk 167 if (!new->pkcs7) { 168 rc = -ENOMEM; 169 goto err; 170 } 171 172 rc = verify_pkcs7_signature(NU 173 #ifdef CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING 174 VE 175 #else 176 NU 177 #endif 178 VE 179 se 180 #ifdef CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING 181 if (rc == -ENOKEY || rc == -EK 182 rc = verify_pkcs7_sign 183 184 185 186 #endif 187 if (rc) 188 goto err; 189 } else { 190 new->textlen = textlen; 191 new->text = kstrdup(text, GFP_ 192 if (!new->text) { 193 rc = -ENOMEM; 194 goto err; 195 } 196 } 197 198 rc = ipe_parse_policy(new); 199 if (rc) 200 goto err; 201 202 return new; 203 err: 204 ipe_free_policy(new); 205 return ERR_PTR(rc); 206 } 207 208 /** 209 * ipe_set_active_pol() - Make @p the active p 210 * @p: Supplies a pointer to the policy to mak 211 * 212 * Context: Requires root->i_rwsem, which i_pr 213 * Return: 214 * * %0 - Success 215 * * %-EINVAL - New active policy version is 216 */ 217 int ipe_set_active_pol(const struct ipe_policy 218 { 219 struct ipe_policy *ap = NULL; 220 221 mutex_lock(&ipe_policy_lock); 222 223 ap = rcu_dereference_protected(ipe_act 224 lockdep 225 if (ap == p) { 226 mutex_unlock(&ipe_policy_lock) 227 return 0; 228 } 229 if (ap && ver_to_u64(ap) > ver_to_u64( 230 mutex_unlock(&ipe_policy_lock) 231 return -EINVAL; 232 } 233 234 rcu_assign_pointer(ipe_active_policy, 235 ipe_audit_policy_activation(ap, p); 236 mutex_unlock(&ipe_policy_lock); 237 238 return 0; 239 } 240
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.