⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 selinuxfs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Updated: Karl MacMillan <kmacmillan@tresys.com> * * 	Added conditional policy language extensions * * Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> *	This program is free software; you can redistribute it and/or modify *  	it under the terms of the GNU General Public License as published by *	the Free Software Foundation, version 2. */#include <linux/kernel.h>#include <linux/pagemap.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/fs.h>#include <linux/mutex.h>#include <linux/init.h>#include <linux/string.h>#include <linux/security.h>#include <linux/major.h>#include <linux/seq_file.h>#include <linux/percpu.h>#include <linux/audit.h>#include <asm/uaccess.h>#include <asm/semaphore.h>/* selinuxfs pseudo filesystem for exporting the security policy API.   Based on the proc code and the fs/nfsd/nfsctl.c code. */#include "flask.h"#include "avc.h"#include "avc_ss.h"#include "security.h"#include "objsec.h"#include "conditional.h"unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT#define SELINUX_COMPAT_NET_VALUE 0#else#define SELINUX_COMPAT_NET_VALUE 1#endifint selinux_compat_net = SELINUX_COMPAT_NET_VALUE;static int __init checkreqprot_setup(char *str){	selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0;	return 1;}__setup("checkreqprot=", checkreqprot_setup);static int __init selinux_compat_net_setup(char *str){	selinux_compat_net = simple_strtoul(str,NULL,0) ? 1 : 0;	return 1;}__setup("selinux_compat_net=", selinux_compat_net_setup);static DEFINE_MUTEX(sel_mutex);/* global data for booleans */static struct dentry *bool_dir = NULL;static int bool_num = 0;static char **bool_pending_names;static int *bool_pending_values = NULL;/* global data for classes */static struct dentry *class_dir = NULL;static unsigned long last_class_ino;extern void selnl_notify_setenforce(int val);/* Check whether a task is allowed to use a security operation. */static int task_has_security(struct task_struct *tsk,			     u32 perms){	struct task_security_struct *tsec;	tsec = tsk->security;	if (!tsec)		return -EACCES;	return avc_has_perm(tsec->sid, SECINITSID_SECURITY,			    SECCLASS_SECURITY, perms, NULL);}enum sel_inos {	SEL_ROOT_INO = 2,	SEL_LOAD,	/* load policy */	SEL_ENFORCE,	/* get or set enforcing status */	SEL_CONTEXT,	/* validate context */	SEL_ACCESS,	/* compute access decision */	SEL_CREATE,	/* compute create labeling decision */	SEL_RELABEL,	/* compute relabeling decision */	SEL_USER,	/* compute reachable user contexts */	SEL_POLICYVERS,	/* return policy version for this kernel */	SEL_COMMIT_BOOLS, /* commit new boolean values */	SEL_MLS,	/* return if MLS policy is enabled */	SEL_DISABLE,	/* disable SELinux until next reboot */	SEL_MEMBER,	/* compute polyinstantiation membership decision */	SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */	SEL_COMPAT_NET,	/* whether to use old compat network packet controls */	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */	SEL_INO_NEXT,	/* The next inode number to use */};static unsigned long sel_last_ino = SEL_INO_NEXT - 1;#define SEL_INITCON_INO_OFFSET 	0x01000000#define SEL_BOOL_INO_OFFSET	0x02000000#define SEL_CLASS_INO_OFFSET	0x04000000#define SEL_INO_MASK		0x00ffffff#define TMPBUFLEN	12static ssize_t sel_read_enforce(struct file *filp, char __user *buf,				size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}#ifdef CONFIG_SECURITY_SELINUX_DEVELOPstatic ssize_t sel_write_enforce(struct file * file, const char __user * buf,				 size_t count, loff_t *ppos){	char *page;	ssize_t length;	int new_value;	if (count >= PAGE_SIZE)		return -ENOMEM;	if (*ppos != 0) {		/* No partial writes. */		return -EINVAL;	}	page = (char*)get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	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 != selinux_enforcing) {		length = task_has_security(current, SECURITY__SETENFORCE);		if (length)			goto out;		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,			"enforcing=%d old_enforcing=%d auid=%u", new_value, 			selinux_enforcing,			audit_get_loginuid(current->audit_context));		selinux_enforcing = new_value;		if (selinux_enforcing)			avc_ss_reset(0);		selnl_notify_setenforce(selinux_enforcing);	}	length = count;out:	free_page((unsigned long) page);	return length;}#else#define sel_write_enforce NULL#endifstatic const struct file_operations sel_enforce_ops = {	.read		= sel_read_enforce,	.write		= sel_write_enforce,};static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,					size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	ino_t ino = filp->f_path.dentry->d_inode->i_ino;	int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?		security_get_reject_unknown() : !security_get_allow_unknown();	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static const struct file_operations sel_handle_unknown_ops = {	.read		= sel_read_handle_unknown,};#ifdef CONFIG_SECURITY_SELINUX_DISABLEstatic ssize_t sel_write_disable(struct file * file, const char __user * buf,				 size_t count, loff_t *ppos){	char *page;	ssize_t length;	int new_value;	extern int selinux_disable(void);	if (count >= PAGE_SIZE)		return -ENOMEM;	if (*ppos != 0) {		/* No partial writes. */		return -EINVAL;	}	page = (char*)get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	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;		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,			"selinux=0 auid=%u",			audit_get_loginuid(current->audit_context));	}	length = count;out:	free_page((unsigned long) page);	return length;}#else#define sel_write_disable NULL#endifstatic const struct file_operations sel_disable_ops = {	.write		= sel_write_disable,};static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,                                   size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static const struct file_operations sel_policyvers_ops = {	.read		= sel_read_policyvers,};/* declaration for sel_write_load */static int sel_make_bools(void);static int sel_make_classes(void);/* declaration for sel_make_class_dirs */static int sel_make_dir(struct inode *dir, struct dentry *dentry,			unsigned long *ino);static ssize_t sel_read_mls(struct file *filp, char __user *buf,				size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static const struct file_operations sel_mls_ops = {	.read		= sel_read_mls,};static ssize_t sel_write_load(struct file * file, const char __user * buf,			      size_t count, loff_t *ppos){	int ret;	ssize_t length;	void *data = NULL;	mutex_lock(&sel_mutex);	length = task_has_security(current, SECURITY__LOAD_POLICY);	if (length)		goto out;	if (*ppos != 0) {		/* No partial writes. */		length = -EINVAL;		goto out;	}	if ((count > 64 * 1024 * 1024)	    || (data = vmalloc(count)) == NULL) {		length = -ENOMEM;		goto out;	}	length = -EFAULT;	if (copy_from_user(data, buf, count) != 0)		goto out;	length = security_load_policy(data, count);	if (length)		goto out;	ret = sel_make_bools();	if (ret) {		length = ret;		goto out1;	}	ret = sel_make_classes();	if (ret)		length = ret;	else		length = count;out1:	printk(KERN_INFO "SELinux: policy loaded with handle_unknown=%s\n",	       (security_get_reject_unknown() ? "reject" :		(security_get_allow_unknown() ? "allow" : "deny")));	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,		"policy loaded auid=%u",		audit_get_loginuid(current->audit_context));out:	mutex_unlock(&sel_mutex);	vfree(data);	return length;}static const struct file_operations sel_load_ops = {	.write		= sel_write_load,};static ssize_t sel_write_context(struct file * file, char *buf, size_t size){	char *canon;	u32 sid, len;	ssize_t length;	length = task_has_security(current, SECURITY__CHECK_CONTEXT);	if (length)		return length;	length = security_context_to_sid(buf, size, &sid);	if (length < 0)		return length;	length = security_sid_to_context(sid, &canon, &len);	if (length < 0)		return length;	if (len > SIMPLE_TRANSACTION_LIMIT) {		printk(KERN_ERR "%s:  context size (%u) exceeds payload "		       "max\n", __FUNCTION__, len);		length = -ERANGE;		goto out;	}	memcpy(buf, canon, len);	length = len;out:	kfree(canon);	return length;}static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,				     size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_checkreqprot);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static ssize_t sel_write_checkreqprot(struct file * file, const char __user * buf,				      size_t count, loff_t *ppos){	char *page;	ssize_t length;	unsigned int new_value;	length = task_has_security(current, SECURITY__SETCHECKREQPROT);	if (length)		return length;	if (count >= PAGE_SIZE)		return -ENOMEM;	if (*ppos != 0) {		/* No partial writes. */		return -EINVAL;	}	page = (char*)get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	length = -EFAULT;	if (copy_from_user(page, buf, count))		goto out;	length = -EINVAL;	if (sscanf(page, "%u", &new_value) != 1)		goto out;	selinux_checkreqprot = new_value ? 1 : 0;	length = count;out:	free_page((unsigned long) page);	return length;}static const struct file_operations sel_checkreqprot_ops = {	.read		= sel_read_checkreqprot,	.write		= sel_write_checkreqprot,};static ssize_t sel_read_compat_net(struct file *filp, char __user *buf,				   size_t count, loff_t *ppos){	char tmpbuf[TMPBUFLEN];	ssize_t length;	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net);	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static ssize_t sel_write_compat_net(struct file * file, const char __user * buf,				    size_t count, loff_t *ppos){	char *page;	ssize_t length;	int new_value;	length = task_has_security(current, SECURITY__LOAD_POLICY);	if (length)		return length;	if (count >= PAGE_SIZE)		return -ENOMEM;	if (*ppos != 0) {		/* No partial writes. */		return -EINVAL;	}	page = (char*)get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	length = -EFAULT;	if (copy_from_user(page, buf, count))		goto out;	length = -EINVAL;	if (sscanf(page, "%d", &new_value) != 1)		goto out;	selinux_compat_net = new_value ? 1 : 0;	length = count;out:	free_page((unsigned long) page);	return length;}static const struct file_operations sel_compat_net_ops = {	.read		= sel_read_compat_net,	.write		= sel_write_compat_net,};/* * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c */static ssize_t sel_write_access(struct file * file, char *buf, size_t size);static ssize_t sel_write_create(struct file * file, char *buf, size_t size);static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size);static ssize_t sel_write_user(struct file * file, char *buf, size_t size);static ssize_t sel_write_member(struct file * file, char *buf, size_t size);static ssize_t (*write_op[])(struct file *, char *, size_t) = {	[SEL_ACCESS] = sel_write_access,	[SEL_CREATE] = sel_write_create,	[SEL_RELABEL] = sel_write_relabel,	[SEL_USER] = sel_write_user,	[SEL_MEMBER] = sel_write_member,	[SEL_CONTEXT] = sel_write_context,};static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos){	ino_t ino =  file->f_path.dentry->d_inode->i_ino;	char *data;	ssize_t rv;	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])		return -EINVAL;	data = simple_transaction_get(file, buf, size);	if (IS_ERR(data))		return PTR_ERR(data);	rv =  write_op[ino](file, data, size);	if (rv>0) {		simple_transaction_set(file, rv);		rv = size;	}	return rv;}static const struct file_operations transaction_ops = {	.write		= selinux_transaction_write,	.read		= simple_transaction_read,	.release	= simple_transaction_release,};/* * payload - write methods * If the method has a response, the response should be put in buf, * and the length returned.  Otherwise return 0 or and -error. */static ssize_t sel_write_access(struct file * file, char *buf, size_t size){	char *scon, *tcon;	u32 ssid, tsid;	u16 tclass;	u32 req;	struct av_decision avd;	ssize_t length;	length = task_has_security(current, SECURITY__COMPUTE_AV);	if (length)		return length;	length = -ENOMEM;	scon = kzalloc(size+1, GFP_KERNEL);	if (!scon)		return length;	tcon = kzalloc(size+1, GFP_KERNEL);	if (!tcon)		goto out;	length = -EINVAL;	if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)		goto out2;	length = security_context_to_sid(scon, strlen(scon)+1, &ssid);	if (length < 0)		goto out2;	length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);	if (length < 0)		goto out2;	length = security_compute_av(ssid, tsid, tclass, req, &avd);	if (length < 0)		goto out2;	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,			  "%x %x %x %x %u",			  avd.allowed, avd.decided,			  avd.auditallow, avd.auditdeny,			  avd.seqno);out2:	kfree(tcon);out:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -