1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. 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 15 /* lock for synchronizing writers across ipe policy */ 16 DEFINE_MUTEX(ipe_policy_lock); 17 18 /** 19 * ver_to_u64() - Convert an internal ipe_policy_version to a u64. 20 * @p: Policy to extract the version from. 21 * 22 * Bits (LSB is index 0): 23 * [48,32] -> Major 24 * [32,16] -> Minor 25 * [16, 0] -> Revision 26 * 27 * Return: u64 version of the embedded version structure. 28 */ 29 static inline u64 ver_to_u64(const struct ipe_policy *const p) 30 { 31 u64 r; 32 33 r = (((u64)p->parsed->version.major) << 32) 34 | (((u64)p->parsed->version.minor) << 16) 35 | ((u64)(p->parsed->version.rev)); 36 37 return r; 38 } 39 40 /** 41 * ipe_free_policy() - Deallocate a given IPE policy. 42 * @p: Supplies the policy to free. 43 * 44 * Safe to call on IS_ERR/NULL. 45 */ 46 void ipe_free_policy(struct ipe_policy *p) 47 { 48 if (IS_ERR_OR_NULL(p)) 49 return; 50 51 ipe_del_policyfs_node(p); 52 ipe_free_parsed_policy(p->parsed); 53 /* 54 * p->text is allocated only when p->pkcs7 is not NULL 55 * otherwise it points to the plaintext data inside the pkcs7 56 */ 57 if (!p->pkcs7) 58 kfree(p->text); 59 kfree(p->pkcs7); 60 kfree(p); 61 } 62 63 static int set_pkcs7_data(void *ctx, const void *data, size_t len, 64 size_t asn1hdrlen __always_unused) 65 { 66 struct ipe_policy *p = ctx; 67 68 p->text = (const char *)data; 69 p->textlen = len; 70 71 return 0; 72 } 73 74 /** 75 * ipe_update_policy() - parse a new policy and replace old with it. 76 * @root: Supplies a pointer to the securityfs inode saved the policy. 77 * @text: Supplies a pointer to the plain text policy. 78 * @textlen: Supplies the length of @text. 79 * @pkcs7: Supplies a pointer to a buffer containing a pkcs7 message. 80 * @pkcs7len: Supplies the length of @pkcs7len. 81 * 82 * @text/@textlen is mutually exclusive with @pkcs7/@pkcs7len - see 83 * ipe_new_policy. 84 * 85 * Context: Requires root->i_rwsem to be held. 86 * Return: %0 on success. If an error occurs, the function will return 87 * the -errno. 88 */ 89 int ipe_update_policy(struct inode *root, const char *text, size_t textlen, 90 const char *pkcs7, size_t pkcs7len) 91 { 92 struct ipe_policy *old, *ap, *new = NULL; 93 int rc = 0; 94 95 old = (struct ipe_policy *)root->i_private; 96 if (!old) 97 return -ENOENT; 98 99 new = ipe_new_policy(text, textlen, pkcs7, pkcs7len); 100 if (IS_ERR(new)) 101 return PTR_ERR(new); 102 103 if (strcmp(new->parsed->name, old->parsed->name)) { 104 rc = -EINVAL; 105 goto err; 106 } 107 108 if (ver_to_u64(old) > ver_to_u64(new)) { 109 rc = -EINVAL; 110 goto err; 111 } 112 113 root->i_private = new; 114 swap(new->policyfs, old->policyfs); 115 116 mutex_lock(&ipe_policy_lock); 117 ap = rcu_dereference_protected(ipe_active_policy, 118 lockdep_is_held(&ipe_policy_lock)); 119 if (old == ap) { 120 rcu_assign_pointer(ipe_active_policy, new); 121 mutex_unlock(&ipe_policy_lock); 122 } else { 123 mutex_unlock(&ipe_policy_lock); 124 } 125 synchronize_rcu(); 126 ipe_free_policy(old); 127 128 return 0; 129 err: 130 ipe_free_policy(new); 131 return rc; 132 } 133 134 /** 135 * ipe_new_policy() - Allocate and parse an ipe_policy structure. 136 * 137 * @text: Supplies a pointer to the plain-text policy to parse. 138 * @textlen: Supplies the length of @text. 139 * @pkcs7: Supplies a pointer to a pkcs7-signed IPE policy. 140 * @pkcs7len: Supplies the length of @pkcs7. 141 * 142 * @text/@textlen Should be NULL/0 if @pkcs7/@pkcs7len is set. 143 * 144 * Return: 145 * * a pointer to the ipe_policy structure - Success 146 * * %-EBADMSG - Policy is invalid 147 * * %-ENOMEM - Out of memory (OOM) 148 * * %-ERANGE - Policy version number overflow 149 * * %-EINVAL - Policy version parsing error 150 */ 151 struct ipe_policy *ipe_new_policy(const char *text, size_t textlen, 152 const char *pkcs7, size_t pkcs7len) 153 { 154 struct ipe_policy *new = NULL; 155 int rc = 0; 156 157 new = kzalloc(sizeof(*new), GFP_KERNEL); 158 if (!new) 159 return ERR_PTR(-ENOMEM); 160 161 if (!text) { 162 new->pkcs7len = pkcs7len; 163 new->pkcs7 = kmemdup(pkcs7, pkcs7len, GFP_KERNEL); 164 if (!new->pkcs7) { 165 rc = -ENOMEM; 166 goto err; 167 } 168 169 rc = verify_pkcs7_signature(NULL, 0, new->pkcs7, pkcs7len, NULL, 170 VERIFYING_UNSPECIFIED_SIGNATURE, 171 set_pkcs7_data, new); 172 if (rc) 173 goto err; 174 } else { 175 new->textlen = textlen; 176 new->text = kstrdup(text, GFP_KERNEL); 177 if (!new->text) { 178 rc = -ENOMEM; 179 goto err; 180 } 181 } 182 183 rc = ipe_parse_policy(new); 184 if (rc) 185 goto err; 186 187 return new; 188 err: 189 ipe_free_policy(new); 190 return ERR_PTR(rc); 191 } 192 193 /** 194 * ipe_set_active_pol() - Make @p the active policy. 195 * @p: Supplies a pointer to the policy to make active. 196 * 197 * Context: Requires root->i_rwsem, which i_private has the policy, to be held. 198 * Return: 199 * * %0 - Success 200 * * %-EINVAL - New active policy version is invalid 201 */ 202 int ipe_set_active_pol(const struct ipe_policy *p) 203 { 204 struct ipe_policy *ap = NULL; 205 206 mutex_lock(&ipe_policy_lock); 207 208 ap = rcu_dereference_protected(ipe_active_policy, 209 lockdep_is_held(&ipe_policy_lock)); 210 if (ap == p) { 211 mutex_unlock(&ipe_policy_lock); 212 return 0; 213 } 214 if (ap && ver_to_u64(ap) > ver_to_u64(p)) { 215 mutex_unlock(&ipe_policy_lock); 216 return -EINVAL; 217 } 218 219 rcu_assign_pointer(ipe_active_policy, p); 220 mutex_unlock(&ipe_policy_lock); 221 222 return 0; 223 } 224