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 #include "audit.h"
15 
16 /* lock for synchronizing writers across ipe policy */
17 DEFINE_MUTEX(ipe_policy_lock);
18 
19 /**
20  * ver_to_u64() - Convert an internal ipe_policy_version to a u64.
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 structure.
29  */
30 static inline u64 ver_to_u64(const struct ipe_policy *const p)
31 {
32 	u64 r;
33 
34 	r = (((u64)p->parsed->version.major) << 32)
35 	  | (((u64)p->parsed->version.minor) << 16)
36 	  | ((u64)(p->parsed->version.rev));
37 
38 	return r;
39 }
40 
41 /**
42  * ipe_free_policy() - Deallocate a given IPE policy.
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->pkcs7 is not NULL
56 	 * otherwise it points to the plaintext data inside the pkcs7
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 void *data, size_t len,
65 			  size_t asn1hdrlen __always_unused)
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 and replace old with it.
77  * @root: Supplies a pointer to the securityfs inode saved the policy.
78  * @text: Supplies a pointer to the plain text policy.
79  * @textlen: Supplies the length of @text.
80  * @pkcs7: Supplies a pointer to a buffer containing a pkcs7 message.
81  * @pkcs7len: Supplies the length of @pkcs7len.
82  *
83  * @text/@textlen is mutually exclusive with @pkcs7/@pkcs7len - see
84  * ipe_new_policy.
85  *
86  * Context: Requires root->i_rwsem to be held.
87  * Return:
88  * * %0	- Success
89  * * %-ENOENT	- Policy was deleted while updating
90  * * %-EINVAL	- Policy name mismatch
91  * * %-ESTALE	- Policy version too old
92  */
93 int ipe_update_policy(struct inode *root, const char *text, size_t textlen,
94 		      const char *pkcs7, size_t pkcs7len)
95 {
96 	struct ipe_policy *old, *ap, *new = NULL;
97 	int rc = 0;
98 
99 	old = (struct ipe_policy *)root->i_private;
100 	if (!old)
101 		return -ENOENT;
102 
103 	new = ipe_new_policy(text, textlen, pkcs7, pkcs7len);
104 	if (IS_ERR(new))
105 		return PTR_ERR(new);
106 
107 	if (strcmp(new->parsed->name, old->parsed->name)) {
108 		rc = -EINVAL;
109 		goto err;
110 	}
111 
112 	if (ver_to_u64(old) >= ver_to_u64(new)) {
113 		rc = -ESTALE;
114 		goto err;
115 	}
116 
117 	root->i_private = new;
118 	swap(new->policyfs, old->policyfs);
119 	ipe_audit_policy_load(new);
120 
121 	mutex_lock(&ipe_policy_lock);
122 	ap = rcu_dereference_protected(ipe_active_policy,
123 				       lockdep_is_held(&ipe_policy_lock));
124 	if (old == ap) {
125 		rcu_assign_pointer(ipe_active_policy, new);
126 		mutex_unlock(&ipe_policy_lock);
127 		ipe_audit_policy_activation(old, new);
128 	} else {
129 		mutex_unlock(&ipe_policy_lock);
130 	}
131 	synchronize_rcu();
132 	ipe_free_policy(old);
133 
134 	return 0;
135 err:
136 	ipe_free_policy(new);
137 	return rc;
138 }
139 
140 /**
141  * ipe_new_policy() - Allocate and parse an ipe_policy structure.
142  *
143  * @text: Supplies a pointer to the plain-text policy to parse.
144  * @textlen: Supplies the length of @text.
145  * @pkcs7: Supplies a pointer to a pkcs7-signed IPE policy.
146  * @pkcs7len: Supplies the length of @pkcs7.
147  *
148  * @text/@textlen Should be NULL/0 if @pkcs7/@pkcs7len is set.
149  *
150  * Return:
151  * * a pointer to the ipe_policy structure	- Success
152  * * %-EBADMSG				- Policy is invalid
153  * * %-ENOMEM				- Out of memory (OOM)
154  * * %-ERANGE				- Policy version number overflow
155  * * %-EINVAL				- Policy version parsing error
156  * * %-ENOKEY				- Policy signing key not found
157  * * %-EKEYREJECTED			- Policy signature verification failed
158  */
159 struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
160 				  const char *pkcs7, size_t pkcs7len)
161 {
162 	struct ipe_policy *new = NULL;
163 	int rc = 0;
164 
165 	new = kzalloc(sizeof(*new), GFP_KERNEL);
166 	if (!new)
167 		return ERR_PTR(-ENOMEM);
168 
169 	if (!text) {
170 		new->pkcs7len = pkcs7len;
171 		new->pkcs7 = kmemdup(pkcs7, pkcs7len, GFP_KERNEL);
172 		if (!new->pkcs7) {
173 			rc = -ENOMEM;
174 			goto err;
175 		}
176 
177 		rc = verify_pkcs7_signature(NULL, 0, new->pkcs7, pkcs7len,
178 #ifdef CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING
179 					    VERIFY_USE_SECONDARY_KEYRING,
180 #else
181 					    NULL,
182 #endif
183 					    VERIFYING_UNSPECIFIED_SIGNATURE,
184 					    set_pkcs7_data, new);
185 #ifdef CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING
186 		if (rc == -ENOKEY || rc == -EKEYREJECTED)
187 			rc = verify_pkcs7_signature(NULL, 0, new->pkcs7, pkcs7len,
188 						    VERIFY_USE_PLATFORM_KEYRING,
189 						    VERIFYING_UNSPECIFIED_SIGNATURE,
190 						    set_pkcs7_data, new);
191 #endif
192 		if (rc)
193 			goto err;
194 	} else {
195 		new->textlen = textlen;
196 		new->text = kstrdup(text, GFP_KERNEL);
197 		if (!new->text) {
198 			rc = -ENOMEM;
199 			goto err;
200 		}
201 	}
202 
203 	rc = ipe_parse_policy(new);
204 	if (rc)
205 		goto err;
206 
207 	return new;
208 err:
209 	ipe_free_policy(new);
210 	return ERR_PTR(rc);
211 }
212 
213 /**
214  * ipe_set_active_pol() - Make @p the active policy.
215  * @p: Supplies a pointer to the policy to make active.
216  *
217  * Context: Requires root->i_rwsem, which i_private has the policy, to be held.
218  * Return:
219  * * %0	- Success
220  * * %-EINVAL	- New active policy version is invalid
221  */
222 int ipe_set_active_pol(const struct ipe_policy *p)
223 {
224 	struct ipe_policy *ap = NULL;
225 
226 	mutex_lock(&ipe_policy_lock);
227 
228 	ap = rcu_dereference_protected(ipe_active_policy,
229 				       lockdep_is_held(&ipe_policy_lock));
230 	if (ap == p) {
231 		mutex_unlock(&ipe_policy_lock);
232 		return 0;
233 	}
234 	if (ap && ver_to_u64(ap) > ver_to_u64(p)) {
235 		mutex_unlock(&ipe_policy_lock);
236 		return -EINVAL;
237 	}
238 
239 	rcu_assign_pointer(ipe_active_policy, p);
240 	ipe_audit_policy_activation(ap, p);
241 	mutex_unlock(&ipe_policy_lock);
242 
243 	return 0;
244 }
245