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

TOMOYO Linux Cross Reference
Linux/security/ipe/policy_fs.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 #include <linux/fs.h>
  6 #include <linux/namei.h>
  7 #include <linux/types.h>
  8 #include <linux/dcache.h>
  9 #include <linux/security.h>
 10 
 11 #include "ipe.h"
 12 #include "policy.h"
 13 #include "eval.h"
 14 #include "fs.h"
 15 
 16 #define MAX_VERSION_SIZE ARRAY_SIZE("65535.65535.65535")
 17 
 18 /**
 19  * ipefs_file - defines a file in securityfs.
 20  */
 21 struct ipefs_file {
 22         const char *name;
 23         umode_t access;
 24         const struct file_operations *fops;
 25 };
 26 
 27 /**
 28  * read_pkcs7() - Read handler for "ipe/policies/$name/pkcs7".
 29  * @f: Supplies a file structure representing the securityfs node.
 30  * @data: Supplies a buffer passed to the write syscall.
 31  * @len: Supplies the length of @data.
 32  * @offset: unused.
 33  *
 34  * @data will be populated with the pkcs7 blob representing the policy
 35  * on success. If the policy is unsigned (like the boot policy), this
 36  * will return -ENOENT.
 37  *
 38  * Return:
 39  * * Length of buffer written   - Success
 40  * * %-ENOENT                   - Policy initializing/deleted or is unsigned
 41  */
 42 static ssize_t read_pkcs7(struct file *f, char __user *data,
 43                           size_t len, loff_t *offset)
 44 {
 45         const struct ipe_policy *p = NULL;
 46         struct inode *root = NULL;
 47         int rc = 0;
 48 
 49         root = d_inode(f->f_path.dentry->d_parent);
 50 
 51         inode_lock_shared(root);
 52         p = (struct ipe_policy *)root->i_private;
 53         if (!p) {
 54                 rc = -ENOENT;
 55                 goto out;
 56         }
 57 
 58         if (!p->pkcs7) {
 59                 rc = -ENOENT;
 60                 goto out;
 61         }
 62 
 63         rc = simple_read_from_buffer(data, len, offset, p->pkcs7, p->pkcs7len);
 64 
 65 out:
 66         inode_unlock_shared(root);
 67 
 68         return rc;
 69 }
 70 
 71 /**
 72  * read_policy() - Read handler for "ipe/policies/$name/policy".
 73  * @f: Supplies a file structure representing the securityfs node.
 74  * @data: Supplies a buffer passed to the write syscall.
 75  * @len: Supplies the length of @data.
 76  * @offset: unused.
 77  *
 78  * @data will be populated with the plain-text version of the policy
 79  * on success.
 80  *
 81  * Return:
 82  * * Length of buffer written   - Success
 83  * * %-ENOENT                   - Policy initializing/deleted
 84  */
 85 static ssize_t read_policy(struct file *f, char __user *data,
 86                            size_t len, loff_t *offset)
 87 {
 88         const struct ipe_policy *p = NULL;
 89         struct inode *root = NULL;
 90         int rc = 0;
 91 
 92         root = d_inode(f->f_path.dentry->d_parent);
 93 
 94         inode_lock_shared(root);
 95         p = (struct ipe_policy *)root->i_private;
 96         if (!p) {
 97                 rc = -ENOENT;
 98                 goto out;
 99         }
100 
101         rc = simple_read_from_buffer(data, len, offset, p->text, p->textlen);
102 
103 out:
104         inode_unlock_shared(root);
105 
106         return rc;
107 }
108 
109 /**
110  * read_name() - Read handler for "ipe/policies/$name/name".
111  * @f: Supplies a file structure representing the securityfs node.
112  * @data: Supplies a buffer passed to the write syscall.
113  * @len: Supplies the length of @data.
114  * @offset: unused.
115  *
116  * @data will be populated with the policy_name attribute on success.
117  *
118  * Return:
119  * * Length of buffer written   - Success
120  * * %-ENOENT                   - Policy initializing/deleted
121  */
122 static ssize_t read_name(struct file *f, char __user *data,
123                          size_t len, loff_t *offset)
124 {
125         const struct ipe_policy *p = NULL;
126         struct inode *root = NULL;
127         int rc = 0;
128 
129         root = d_inode(f->f_path.dentry->d_parent);
130 
131         inode_lock_shared(root);
132         p = (struct ipe_policy *)root->i_private;
133         if (!p) {
134                 rc = -ENOENT;
135                 goto out;
136         }
137 
138         rc = simple_read_from_buffer(data, len, offset, p->parsed->name,
139                                      strlen(p->parsed->name));
140 
141 out:
142         inode_unlock_shared(root);
143 
144         return rc;
145 }
146 
147 /**
148  * read_version() - Read handler for "ipe/policies/$name/version".
149  * @f: Supplies a file structure representing the securityfs node.
150  * @data: Supplies a buffer passed to the write syscall.
151  * @len: Supplies the length of @data.
152  * @offset: unused.
153  *
154  * @data will be populated with the version string on success.
155  *
156  * Return:
157  * * Length of buffer written   - Success
158  * * %-ENOENT                   - Policy initializing/deleted
159  */
160 static ssize_t read_version(struct file *f, char __user *data,
161                             size_t len, loff_t *offset)
162 {
163         char buffer[MAX_VERSION_SIZE] = { 0 };
164         const struct ipe_policy *p = NULL;
165         struct inode *root = NULL;
166         size_t strsize = 0;
167         ssize_t rc = 0;
168 
169         root = d_inode(f->f_path.dentry->d_parent);
170 
171         inode_lock_shared(root);
172         p = (struct ipe_policy *)root->i_private;
173         if (!p) {
174                 rc = -ENOENT;
175                 goto out;
176         }
177 
178         strsize = scnprintf(buffer, ARRAY_SIZE(buffer), "%hu.%hu.%hu",
179                             p->parsed->version.major, p->parsed->version.minor,
180                             p->parsed->version.rev);
181 
182         rc = simple_read_from_buffer(data, len, offset, buffer, strsize);
183 
184 out:
185         inode_unlock_shared(root);
186 
187         return rc;
188 }
189 
190 /**
191  * setactive() - Write handler for "ipe/policies/$name/active".
192  * @f: Supplies a file structure representing the securityfs node.
193  * @data: Supplies a buffer passed to the write syscall.
194  * @len: Supplies the length of @data.
195  * @offset: unused.
196  *
197  * Return:
198  * * Length of buffer written   - Success
199  * * %-EPERM                    - Insufficient permission
200  * * %-EINVAL                   - Invalid input
201  * * %-ENOENT                   - Policy initializing/deleted
202  */
203 static ssize_t setactive(struct file *f, const char __user *data,
204                          size_t len, loff_t *offset)
205 {
206         const struct ipe_policy *p = NULL;
207         struct inode *root = NULL;
208         bool value = false;
209         int rc = 0;
210 
211         if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
212                 return -EPERM;
213 
214         rc = kstrtobool_from_user(data, len, &value);
215         if (rc)
216                 return rc;
217 
218         if (!value)
219                 return -EINVAL;
220 
221         root = d_inode(f->f_path.dentry->d_parent);
222         inode_lock(root);
223 
224         p = (struct ipe_policy *)root->i_private;
225         if (!p) {
226                 rc = -ENOENT;
227                 goto out;
228         }
229 
230         rc = ipe_set_active_pol(p);
231 
232 out:
233         inode_unlock(root);
234         return (rc < 0) ? rc : len;
235 }
236 
237 /**
238  * getactive() - Read handler for "ipe/policies/$name/active".
239  * @f: Supplies a file structure representing the securityfs node.
240  * @data: Supplies a buffer passed to the write syscall.
241  * @len: Supplies the length of @data.
242  * @offset: unused.
243  *
244  * @data will be populated with the 1 or 0 depending on if the
245  * corresponding policy is active.
246  *
247  * Return:
248  * * Length of buffer written   - Success
249  * * %-ENOENT                   - Policy initializing/deleted
250  */
251 static ssize_t getactive(struct file *f, char __user *data,
252                          size_t len, loff_t *offset)
253 {
254         const struct ipe_policy *p = NULL;
255         struct inode *root = NULL;
256         const char *str;
257         int rc = 0;
258 
259         root = d_inode(f->f_path.dentry->d_parent);
260 
261         inode_lock_shared(root);
262         p = (struct ipe_policy *)root->i_private;
263         if (!p) {
264                 inode_unlock_shared(root);
265                 return -ENOENT;
266         }
267         inode_unlock_shared(root);
268 
269         str = (p == rcu_access_pointer(ipe_active_policy)) ? "1" : "";
270         rc = simple_read_from_buffer(data, len, offset, str, 1);
271 
272         return rc;
273 }
274 
275 /**
276  * update_policy() - Write handler for "ipe/policies/$name/update".
277  * @f: Supplies a file structure representing the securityfs node.
278  * @data: Supplies a buffer passed to the write syscall.
279  * @len: Supplies the length of @data.
280  * @offset: unused.
281  *
282  * On success this updates the policy represented by $name,
283  * in-place.
284  *
285  * Return: Length of buffer written on success. If an error occurs,
286  * the function will return the -errno.
287  */
288 static ssize_t update_policy(struct file *f, const char __user *data,
289                              size_t len, loff_t *offset)
290 {
291         struct inode *root = NULL;
292         char *copy = NULL;
293         int rc = 0;
294 
295         if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
296                 return -EPERM;
297 
298         copy = memdup_user(data, len);
299         if (IS_ERR(copy))
300                 return PTR_ERR(copy);
301 
302         root = d_inode(f->f_path.dentry->d_parent);
303         inode_lock(root);
304         rc = ipe_update_policy(root, NULL, 0, copy, len);
305         inode_unlock(root);
306 
307         kfree(copy);
308         if (rc)
309                 return rc;
310 
311         return len;
312 }
313 
314 /**
315  * delete_policy() - write handler for  "ipe/policies/$name/delete".
316  * @f: Supplies a file structure representing the securityfs node.
317  * @data: Supplies a buffer passed to the write syscall.
318  * @len: Supplies the length of @data.
319  * @offset: unused.
320  *
321  * On success this deletes the policy represented by $name.
322  *
323  * Return:
324  * * Length of buffer written   - Success
325  * * %-EPERM                    - Insufficient permission/deleting active policy
326  * * %-EINVAL                   - Invalid input
327  * * %-ENOENT                   - Policy initializing/deleted
328  */
329 static ssize_t delete_policy(struct file *f, const char __user *data,
330                              size_t len, loff_t *offset)
331 {
332         struct ipe_policy *ap = NULL;
333         struct ipe_policy *p = NULL;
334         struct inode *root = NULL;
335         bool value = false;
336         int rc = 0;
337 
338         if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
339                 return -EPERM;
340 
341         rc = kstrtobool_from_user(data, len, &value);
342         if (rc)
343                 return rc;
344 
345         if (!value)
346                 return -EINVAL;
347 
348         root = d_inode(f->f_path.dentry->d_parent);
349         inode_lock(root);
350         p = (struct ipe_policy *)root->i_private;
351         if (!p) {
352                 inode_unlock(root);
353                 return -ENOENT;
354         }
355 
356         mutex_lock(&ipe_policy_lock);
357         ap = rcu_dereference_protected(ipe_active_policy,
358                                        lockdep_is_held(&ipe_policy_lock));
359         if (p == ap) {
360                 mutex_unlock(&ipe_policy_lock);
361                 inode_unlock(root);
362                 return -EPERM;
363         }
364         mutex_unlock(&ipe_policy_lock);
365 
366         root->i_private = NULL;
367         inode_unlock(root);
368 
369         synchronize_rcu();
370         ipe_free_policy(p);
371 
372         return len;
373 }
374 
375 static const struct file_operations content_fops = {
376         .read = read_policy,
377 };
378 
379 static const struct file_operations pkcs7_fops = {
380         .read = read_pkcs7,
381 };
382 
383 static const struct file_operations name_fops = {
384         .read = read_name,
385 };
386 
387 static const struct file_operations ver_fops = {
388         .read = read_version,
389 };
390 
391 static const struct file_operations active_fops = {
392         .write = setactive,
393         .read = getactive,
394 };
395 
396 static const struct file_operations update_fops = {
397         .write = update_policy,
398 };
399 
400 static const struct file_operations delete_fops = {
401         .write = delete_policy,
402 };
403 
404 /**
405  * policy_subdir - files under a policy subdirectory
406  */
407 static const struct ipefs_file policy_subdir[] = {
408         { "pkcs7", 0444, &pkcs7_fops },
409         { "policy", 0444, &content_fops },
410         { "name", 0444, &name_fops },
411         { "version", 0444, &ver_fops },
412         { "active", 0600, &active_fops },
413         { "update", 0200, &update_fops },
414         { "delete", 0200, &delete_fops },
415 };
416 
417 /**
418  * ipe_del_policyfs_node() - Delete a securityfs entry for @p.
419  * @p: Supplies a pointer to the policy to delete a securityfs entry for.
420  */
421 void ipe_del_policyfs_node(struct ipe_policy *p)
422 {
423         securityfs_recursive_remove(p->policyfs);
424         p->policyfs = NULL;
425 }
426 
427 /**
428  * ipe_new_policyfs_node() - Create a securityfs entry for @p.
429  * @p: Supplies a pointer to the policy to create a securityfs entry for.
430  *
431  * Return: %0 on success. If an error occurs, the function will return
432  * the -errno.
433  */
434 int ipe_new_policyfs_node(struct ipe_policy *p)
435 {
436         const struct ipefs_file *f = NULL;
437         struct dentry *policyfs = NULL;
438         struct inode *root = NULL;
439         struct dentry *d = NULL;
440         size_t i = 0;
441         int rc = 0;
442 
443         if (p->policyfs)
444                 return 0;
445 
446         policyfs = securityfs_create_dir(p->parsed->name, policy_root);
447         if (IS_ERR(policyfs))
448                 return PTR_ERR(policyfs);
449 
450         root = d_inode(policyfs);
451 
452         for (i = 0; i < ARRAY_SIZE(policy_subdir); ++i) {
453                 f = &policy_subdir[i];
454 
455                 d = securityfs_create_file(f->name, f->access, policyfs,
456                                            NULL, f->fops);
457                 if (IS_ERR(d)) {
458                         rc = PTR_ERR(d);
459                         goto err;
460                 }
461         }
462 
463         inode_lock(root);
464         p->policyfs = policyfs;
465         root->i_private = p;
466         inode_unlock(root);
467 
468         return 0;
469 err:
470         securityfs_recursive_remove(policyfs);
471         return rc;
472 }
473 

~ [ 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