Enable users to manage SELinux policies through the new hook lsm_config_system_policy. This feature is restricted to CAP_MAC_ADMIN.
Signed-off-by: Maxime Bélair <[email protected]> --- security/selinux/hooks.c | 27 +++++++++++++++++++++++++++ security/selinux/include/security.h | 7 +++++++ security/selinux/selinuxfs.c | 16 ++++++++++++---- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e7a7dcab81db..3d14d4e47937 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -7196,6 +7196,31 @@ static int selinux_uring_allowed(void) } #endif /* CONFIG_IO_URING */ +/** + * selinux_lsm_config_system_policy - Manage a LSM policy + * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported + * @buf: User-supplied buffer + * @size: size of @buf + * @flags: reserved for future use; must be zero + * + * Returns: number of written rules on success, negative value on error + */ +static int selinux_lsm_config_system_policy(u32 op, void __user *buf, + size_t size, u32 flags) +{ + loff_t pos = 0; + + if (op != LSM_POLICY_LOAD || flags) + return -EOPNOTSUPP; + + if (!selinux_null.dentry || !selinux_null.dentry->d_sb || + !selinux_null.dentry->d_sb->s_fs_info) + return -ENODEV; + + return __sel_write_load(selinux_null.dentry->d_sb->s_fs_info, buf, size, + &pos); +} + static const struct lsm_id selinux_lsmid = { .name = "selinux", .id = LSM_ID_SELINUX, @@ -7499,6 +7524,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { #ifdef CONFIG_PERF_EVENTS LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), #endif + LSM_HOOK_INIT(lsm_config_system_policy, selinux_lsm_config_system_policy), + }; static __init int selinux_init(void) diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index e7827ed7be5f..7b779ea43cc3 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -389,7 +389,14 @@ struct selinux_kernel_status { extern void selinux_status_update_setenforce(bool enforcing); extern void selinux_status_update_policyload(u32 seqno); extern void selinux_complete_init(void); + +struct selinux_fs_info; + extern struct path selinux_null; +extern ssize_t __sel_write_load(struct selinux_fs_info *fsi, + const char __user *buf, size_t count, + loff_t *ppos); + extern void selnl_notify_setenforce(int val); extern void selnl_notify_policyload(u32 seqno); extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 47480eb2189b..1f7e611d8300 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -567,11 +567,11 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi, return ret; } -static ssize_t sel_write_load(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +ssize_t __sel_write_load(struct selinux_fs_info *fsi, + const char __user *buf, size_t count, + loff_t *ppos) { - struct selinux_fs_info *fsi; struct selinux_load_state load_state; ssize_t length; void *data = NULL; @@ -605,7 +605,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, pr_warn_ratelimited("SELinux: failed to load policy\n"); goto out; } - fsi = file_inode(file)->i_sb->s_fs_info; length = sel_make_policy_nodes(fsi, load_state.policy); if (length) { pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n"); @@ -626,6 +625,15 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, return length; } +static ssize_t sel_write_load(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; + + return __sel_write_load(fsi, buf, count, ppos); +} + + static const struct file_operations sel_load_ops = { .write = sel_write_load, .llseek = generic_file_llseek, -- 2.48.1
