]> Git Repo - linux.git/blob - security/ipe/policy_fs.c
Linux 6.14-rc3
[linux.git] / security / ipe / policy_fs.c
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" : "0";
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 }
This page took 0.059134 seconds and 4 git commands to generate.