Commit c59f3ad7 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] selinux: add runtime disable

From: Stephen Smalley <sds@epoch.ncsc.mil>

This patch adds a kernel configuration option that enables writing to a new
selinuxfs node 'disable' that allows SELinux to be disabled at runtime prior
to initial policy load.  SELinux will then remain disabled until next boot.
This option is similar to the selinux=0 boot parameter, but is to support
runtime disabling of SELinux, e.g.  from /sbin/init, for portability across
platforms where boot parameters are difficult to employ (based on feedback by
Jeremy Katz).
parent 77782961
......@@ -24,6 +24,21 @@ config SECURITY_SELINUX_BOOTPARAM
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
default n
help
This option enables writing to a selinuxfs node 'disable', which
allows SELinux to be disabled at runtime prior to the policy load.
SELinux will then remain disabled until the next boot.
This option is similar to the selinux=0 boot parameter, but is to
support runtime disabling of SELinux, e.g. from /sbin/init, for
portability across platforms where boot parameters are difficult
to employ.
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
bool "NSA SELinux Development Support"
depends on SECURITY_SELINUX
......
......@@ -4216,4 +4216,57 @@ static int __init selinux_nf_ip_init(void)
__initcall(selinux_nf_ip_init);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static void selinux_nf_ip_exit(void)
{
printk(KERN_INFO "SELinux: Unregistering netfilter hooks\n");
nf_unregister_hook(&selinux_ipv4_op);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
nf_unregister_hook(&selinux_ipv6_op);
#endif /* IPV6 */
}
#endif
#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
#define selinux_nf_ip_exit()
#endif
#endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
int selinux_disable(void)
{
extern void exit_sel_fs(void);
static int selinux_disabled = 0;
if (ss_initialized) {
/* Not permitted after initial policy load. */
return -EINVAL;
}
if (selinux_disabled) {
/* Only do this once. */
return -EINVAL;
}
printk(KERN_INFO "SELinux: Disabled at runtime.\n");
selinux_disabled = 1;
/* Reset security_ops to the secondary module, dummy or capability. */
security_ops = secondary_ops;
/* Unregister netfilter hooks. */
selinux_nf_ip_exit();
/* Unregister selinuxfs. */
exit_sel_fs();
return 0;
}
#endif
......@@ -46,6 +46,8 @@ int task_has_security(struct task_struct *tsk,
struct task_security_struct *tsec;
tsec = tsk->security;
if (!tsec)
return -EACCES;
return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
SECCLASS_SECURITY, perms, NULL, NULL);
......@@ -61,8 +63,9 @@ enum sel_inos {
SEL_RELABEL, /* compute relabeling decision */
SEL_USER, /* compute reachable user contexts */
SEL_POLICYVERS, /* return policy version for this kernel */
SEL_COMMIT_BOOLS,
SEL_MLS /* return if MLS policy is enabled */
SEL_COMMIT_BOOLS, /* commit new boolean values */
SEL_MLS, /* return if MLS policy is enabled */
SEL_DISABLE /* disable SELinux until next reboot */
};
static ssize_t sel_read_enforce(struct file *filp, char *buf,
......@@ -151,6 +154,53 @@ static struct file_operations sel_enforce_ops = {
.write = sel_write_enforce,
};
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static ssize_t sel_write_disable(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
char *page;
ssize_t length;
int new_value;
extern int selinux_disable(void);
if (count < 0 || count >= PAGE_SIZE)
return -ENOMEM;
if (*ppos != 0) {
/* No partial writes. */
return -EINVAL;
}
page = (char*)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
memset(page, 0, PAGE_SIZE);
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
if (new_value) {
length = selinux_disable();
if (length < 0)
goto out;
}
length = count;
out:
free_page((unsigned long) page);
return length;
}
#else
#define sel_write_disable NULL
#endif
static struct file_operations sel_disable_ops = {
.write = sel_write_disable,
};
static ssize_t sel_read_policyvers(struct file *filp, char *buf,
size_t count, loff_t *ppos)
{
......@@ -1005,6 +1055,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
[SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
......@@ -1054,3 +1105,10 @@ static int __init init_sel_fs(void)
}
__initcall(init_sel_fs);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
unregister_filesystem(&sel_fs_type);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment