~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/ipe/policy.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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: %0 on success. If an error occurs, the function will return
 88  * the -errno.
 89  */
 90 int ipe_update_policy(struct inode *root, const char *text, size_t textlen,
 91                       const char *pkcs7, size_t pkcs7len)
 92 {
 93         struct ipe_policy *old, *ap, *new = NULL;
 94         int rc = 0;
 95 
 96         old = (struct ipe_policy *)root->i_private;
 97         if (!old)
 98                 return -ENOENT;
 99 
100         new = ipe_new_policy(text, textlen, pkcs7, pkcs7len);
101         if (IS_ERR(new))
102                 return PTR_ERR(new);
103 
104         if (strcmp(new->parsed->name, old->parsed->name)) {
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_active_policy,
120                                        lockdep_is_held(&ipe_policy_lock));
121         if (old == ap) {
122                 rcu_assign_pointer(ipe_active_policy, new);
123                 mutex_unlock(&ipe_policy_lock);
124                 ipe_audit_policy_activation(old, new);
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 ipe_policy structure.
139  *
140  * @text: Supplies a pointer to the plain-text policy to parse.
141  * @textlen: Supplies the length of @text.
142  * @pkcs7: Supplies a pointer to a pkcs7-signed IPE policy.
143  * @pkcs7len: Supplies the length of @pkcs7.
144  *
145  * @text/@textlen Should be NULL/0 if @pkcs7/@pkcs7len is set.
146  *
147  * Return:
148  * * a pointer to the ipe_policy structure      - Success
149  * * %-EBADMSG                                  - Policy is invalid
150  * * %-ENOMEM                                   - Out of memory (OOM)
151  * * %-ERANGE                                   - Policy version number overflow
152  * * %-EINVAL                                   - Policy version parsing error
153  */
154 struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
155                                   const char *pkcs7, size_t pkcs7len)
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, pkcs7len, GFP_KERNEL);
167                 if (!new->pkcs7) {
168                         rc = -ENOMEM;
169                         goto err;
170                 }
171 
172                 rc = verify_pkcs7_signature(NULL, 0, new->pkcs7, pkcs7len,
173 #ifdef CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING
174                                             VERIFY_USE_SECONDARY_KEYRING,
175 #else
176                                             NULL,
177 #endif
178                                             VERIFYING_UNSPECIFIED_SIGNATURE,
179                                             set_pkcs7_data, new);
180 #ifdef CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING
181                 if (rc == -ENOKEY || rc == -EKEYREJECTED)
182                         rc = verify_pkcs7_signature(NULL, 0, new->pkcs7, pkcs7len,
183                                                     VERIFY_USE_PLATFORM_KEYRING,
184                                                     VERIFYING_UNSPECIFIED_SIGNATURE,
185                                                     set_pkcs7_data, new);
186 #endif
187                 if (rc)
188                         goto err;
189         } else {
190                 new->textlen = textlen;
191                 new->text = kstrdup(text, GFP_KERNEL);
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 policy.
210  * @p: Supplies a pointer to the policy to make active.
211  *
212  * Context: Requires root->i_rwsem, which i_private has the policy, to be held.
213  * Return:
214  * * %0 - Success
215  * * %-EINVAL   - New active policy version is invalid
216  */
217 int ipe_set_active_pol(const struct ipe_policy *p)
218 {
219         struct ipe_policy *ap = NULL;
220 
221         mutex_lock(&ipe_policy_lock);
222 
223         ap = rcu_dereference_protected(ipe_active_policy,
224                                        lockdep_is_held(&ipe_policy_lock));
225         if (ap == p) {
226                 mutex_unlock(&ipe_policy_lock);
227                 return 0;
228         }
229         if (ap && ver_to_u64(ap) > ver_to_u64(p)) {
230                 mutex_unlock(&ipe_policy_lock);
231                 return -EINVAL;
232         }
233 
234         rcu_assign_pointer(ipe_active_policy, p);
235         ipe_audit_policy_activation(ap, p);
236         mutex_unlock(&ipe_policy_lock);
237 
238         return 0;
239 }
240 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php