* the Free Software Foundation, version 2.
*/
+#include <linux/config.h>
#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>
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
-#endif
-
-int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
-
static int __init checkreqprot_setup(char *str)
{
selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0;
}
__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);
+static DECLARE_MUTEX(sel_sem);
/* global data for booleans */
static struct dentry *bool_dir = NULL;
SEL_AVC, /* AVC management directory */
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 */
};
#define TMPBUFLEN 12
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);
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;
ssize_t length;
void *data = NULL;
- mutex_lock(&sel_mutex);
+ down(&sel_sem);
length = task_has_security(current, SECURITY__LOAD_POLICY);
if (length)
length = ret;
else
length = count;
- 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);
+ up(&sel_sem);
vfree(data);
return length;
}
.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 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
*/
if (ret) {
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
+ ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
{
char *page = NULL;
ssize_t length;
+ ssize_t end;
ssize_t ret;
int cur_enforcing;
struct inode *inode;
- mutex_lock(&sel_mutex);
+ down(&sel_sem);
ret = -EFAULT;
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
- ret = simple_read_from_buffer(buf, count, ppos, page, length);
+ if (length < 0) {
+ ret = length;
+ goto out;
+ }
+
+ if (*ppos >= length) {
+ ret = 0;
+ goto out;
+ }
+ if (count + *ppos > length)
+ count = length - *ppos;
+ end = count + *ppos;
+ if (copy_to_user(buf, (char *) page + *ppos, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ *ppos = end;
+ ret = count;
out:
- mutex_unlock(&sel_mutex);
+ up(&sel_sem);
if (page)
free_page((unsigned long)page);
return ret;
int new_value;
struct inode *inode;
- mutex_lock(&sel_mutex);
+ down(&sel_sem);
length = task_has_security(current, SECURITY__SETBOOL);
if (length)
length = count;
out:
- mutex_unlock(&sel_mutex);
+ up(&sel_sem);
if (page)
free_page((unsigned long) page);
return length;
ssize_t length = -EFAULT;
int new_value;
- mutex_lock(&sel_mutex);
+ down(&sel_sem);
length = task_has_security(current, SECURITY__SETBOOL);
if (length)
length = count;
out:
- mutex_unlock(&sel_mutex);
+ up(&sel_sem);
if (page)
free_page((unsigned long) page);
return length;
return ret;
err:
kfree(values);
- sel_remove_bools(dir);
+ d_genocide(dir);
ret = -ENOMEM;
goto out;
}
dentry = d_alloc_name(dir, files[i].name);
if (!dentry) {
ret = -ENOMEM;
- goto out;
+ goto err;
}
inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
if (!inode) {
ret = -ENOMEM;
- goto out;
+ goto err;
}
inode->i_fop = files[i].ops;
d_add(dentry, inode);
}
out:
return ret;
+err:
+ d_genocide(dir);
+ goto out;
}
-static int sel_make_dir(struct inode *dir, struct dentry *dentry)
+static int sel_make_dir(struct super_block *sb, struct dentry *dentry)
{
int ret = 0;
struct inode *inode;
- inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
+ inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
if (!inode) {
ret = -ENOMEM;
goto out;
}
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
d_add(dentry, inode);
- /* bump link count on parent directory, too */
- dir->i_nlink++;
out:
return ret;
}
{
int ret;
struct dentry *dentry;
- struct inode *inode, *root_inode;
+ struct inode *inode;
struct inode_security_struct *isec;
static struct tree_descr selinux_files[] = {
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
- [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
if (ret)
- goto err;
-
- root_inode = sb->s_root->d_inode;
+ return ret;
dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
- if (!dentry) {
- ret = -ENOMEM;
- goto err;
- }
-
- ret = sel_make_dir(root_inode, dentry);
- if (ret)
- goto err;
+ if (!dentry)
+ return -ENOMEM;
+ inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
+ if (!inode)
+ goto out;
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ d_add(dentry, inode);
bool_dir = dentry;
+ ret = sel_make_bools();
+ if (ret)
+ goto out;
dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
- if (!dentry) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!dentry)
+ return -ENOMEM;
inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
- if (!inode) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!inode)
+ goto out;
isec = (struct inode_security_struct*)inode->i_security;
isec->sid = SECINITSID_DEVNULL;
isec->sclass = SECCLASS_CHR_FILE;
selinux_null = dentry;
dentry = d_alloc_name(sb->s_root, "avc");
- if (!dentry) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!dentry)
+ return -ENOMEM;
- ret = sel_make_dir(root_inode, dentry);
+ ret = sel_make_dir(sb, dentry);
if (ret)
- goto err;
+ goto out;
ret = sel_make_avc_files(dentry);
if (ret)
- goto err;
+ goto out;
+
+ return 0;
out:
- return ret;
-err:
+ dput(dentry);
printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__);
- goto out;
+ return -ENOMEM;
}
-static int sel_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data,
- struct vfsmount *mnt)
+static struct super_block *sel_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
+ return get_sb_single(fs_type, flags, data, sel_fill_super);
}
static struct file_system_type sel_fs_type = {