Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. */
#include <linux/dcache.h>#include <linux/security.h>
#include "ipe.h"#include "fs.h"#include "eval.h"#include "policy.h"#include "audit.h"
static struct dentry *root __ro_after_init;struct dentry *policy_root __ro_after_init;
/** * setaudit() - Write handler for the securityfs node, "ipe/success_audit" * @f: Supplies a file structure representing the securityfs node. * @data: Supplies a buffer passed to the write syscall. * @len: Supplies the length of @data. * @offset: unused. * * Return: * * Length of buffer written - Success * * %-EPERM - Insufficient permission */static ssize_t setaudit(struct file *f, const char __user *data, size_t len, loff_t *offset){ int rc = 0; bool value;
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) return -EPERM;
rc = kstrtobool_from_user(data, len, &value); if (rc) return rc;
WRITE_ONCE(success_audit, value);
return len;}
/** * getaudit() - Read handler for the securityfs node, "ipe/success_audit" * @f: Supplies a file structure representing the securityfs node. * @data: Supplies a buffer passed to the read syscall. * @len: Supplies the length of @data. * @offset: unused. * * Return: Length of buffer written */static ssize_t getaudit(struct file *f, char __user *data, size_t len, loff_t *offset){ const char *result;
result = ((READ_ONCE(success_audit)) ? "1" : "0");
return simple_read_from_buffer(data, len, offset, result, 1);}
/** * setenforce() - Write handler for the securityfs node, "ipe/enforce" * @f: Supplies a file structure representing the securityfs node. * @data: Supplies a buffer passed to the write syscall. * @len: Supplies the length of @data. * @offset: unused. * * Return: * * Length of buffer written - Success * * %-EPERM - Insufficient permission */static ssize_t setenforce(struct file *f, const char __user *data, size_t len, loff_t *offset){ int rc = 0; bool new_value, old_value;
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) return -EPERM;
old_value = READ_ONCE(enforce); rc = kstrtobool_from_user(data, len, &new_value); if (rc) return rc;
if (new_value != old_value) { ipe_audit_enforce(new_value, old_value); WRITE_ONCE(enforce, new_value); }
return len;}
/** * getenforce() - Read handler for the securityfs node, "ipe/enforce" * @f: Supplies a file structure representing the securityfs node. * @data: Supplies a buffer passed to the read syscall. * @len: Supplies the length of @data. * @offset: unused. * * Return: Length of buffer written */static ssize_t getenforce(struct file *f, char __user *data, size_t len, loff_t *offset){ const char *result;
result = ((READ_ONCE(enforce)) ? "1" : "0");
return simple_read_from_buffer(data, len, offset, result, 1);}
/** * new_policy() - Write handler for the securityfs node, "ipe/new_policy". * @f: Supplies a file structure representing the securityfs node. * @data: Supplies a buffer passed to the write syscall. * @len: Supplies the length of @data. * @offset: unused. * * Return: * * Length of buffer written - Success * * %-EPERM - Insufficient permission * * %-ENOMEM - Out of memory (OOM) * * %-EBADMSG - Policy is invalid * * %-ERANGE - Policy version number overflow * * %-EINVAL - Policy version parsing error * * %-EEXIST - Same name policy already deployed * * %-ENOKEY - Policy signing key not found * * %-EKEYREJECTED - Policy signature verification failed */static ssize_t new_policy(struct file *f, const char __user *data, size_t len, loff_t *offset){ struct ipe_policy *p = NULL; char *copy = NULL; int rc = 0;
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) { rc = -EPERM; goto out; }
copy = memdup_user_nul(data, len); if (IS_ERR(copy)) { rc = PTR_ERR(copy); copy = NULL; goto out; }
p = ipe_new_policy(NULL, 0, copy, len); if (IS_ERR(p)) { rc = PTR_ERR(p); goto out; }
rc = ipe_new_policyfs_node(p); if (rc) goto out;
out: kfree(copy); if (rc < 0) { ipe_free_policy(p); ipe_audit_policy_load(ERR_PTR(rc)); } else { ipe_audit_policy_load(p); } return (rc < 0) ? rc : len;}
static const struct file_operations np_fops = { .write = new_policy,};
static const struct file_operations audit_fops = { .write = setaudit, .read = getaudit,};
static const struct file_operations enforce_fops = { .write = setenforce, .read = getenforce,};
/** * ipe_init_securityfs() - Initialize IPE's securityfs tree at fsinit. * * Return: %0 on success. If an error occurs, the function will return * the -errno. */int __init ipe_init_securityfs(void){ int rc = 0; struct ipe_policy *ap; struct dentry *dentry;
if (!ipe_enabled) return -EOPNOTSUPP;
root = securityfs_create_dir("ipe", NULL); if (IS_ERR(root)) return PTR_ERR(root);
dentry = securityfs_create_file("success_audit", 0600, root, NULL, &audit_fops); if (IS_ERR(dentry)) { rc = PTR_ERR(dentry); goto err; }
dentry = securityfs_create_file("enforce", 0600, root, NULL, &enforce_fops); if (IS_ERR(dentry)) { rc = PTR_ERR(dentry); goto err; }
policy_root = securityfs_create_dir("policies", root); if (IS_ERR(policy_root)) { rc = PTR_ERR(policy_root); goto err; }
ap = rcu_access_pointer(ipe_active_policy); if (ap) { rc = ipe_new_policyfs_node(ap); if (rc) goto err; }
dentry = securityfs_create_file("new_policy", 0200, root, NULL, &np_fops); if (IS_ERR(dentry)) { rc = PTR_ERR(dentry); goto err; }
return 0;err: securityfs_remove(root); return rc;}