File Index
Files and directories
Sign in
FILE

policy_fs.c

File preview with syntax highlighting.

linux-6.19.14/security/ipe/policy_fs.c 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#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}
~/ Read-only file preview.