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