* the Free Software Foundation, version 2.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/slab.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);
SEL_COMMIT_BOOLS, /* commit new boolean values */
SEL_MLS, /* return if MLS policy is enabled */
SEL_DISABLE, /* disable SELinux until next reboot */
- 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 */
+ 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_INO_MASK 0x00ffffff
+
#define TMPBUFLEN 12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
#define sel_write_enforce NULL
#endif
-static struct file_operations sel_enforce_ops = {
+static const struct file_operations sel_enforce_ops = {
.read = sel_read_enforce,
.write = sel_write_enforce,
};
#define sel_write_disable NULL
#endif
-static struct file_operations sel_disable_ops = {
+static const struct file_operations sel_disable_ops = {
.write = sel_write_disable,
};
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
-static struct file_operations sel_policyvers_ops = {
+static const struct file_operations sel_policyvers_ops = {
.read = sel_read_policyvers,
};
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
-static struct file_operations sel_mls_ops = {
+static const struct file_operations sel_mls_ops = {
.read = sel_read_mls,
};
return length;
}
-static struct file_operations sel_load_ops = {
+static const struct file_operations sel_load_ops = {
.write = sel_write_load,
};
free_page((unsigned long) page);
return length;
}
-static struct file_operations sel_checkreqprot_ops = {
+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 selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
- ino_t ino = file->f_dentry->d_inode->i_ino;
+ ino_t ino = file->f_path.dentry->d_inode->i_ino;
char *data;
ssize_t rv;
return rv;
}
-static struct file_operations transaction_ops = {
+static const struct file_operations transaction_ops = {
.write = selinux_transaction_write,
.read = simple_transaction_read,
.release = simple_transaction_release,
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;
}
return ret;
}
-#define BOOL_INO_OFFSET 30
-
static ssize_t sel_read_bool(struct file *filep, char __user *buf,
size_t count, loff_t *ppos)
{
goto out;
}
- inode = filep->f_dentry->d_inode;
- cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
+ inode = filep->f_path.dentry->d_inode;
+ cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
if (cur_enforcing < 0) {
ret = cur_enforcing;
goto out;
}
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
- bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
+ bool_pending_values[inode->i_ino&SEL_INO_MASK]);
ret = simple_read_from_buffer(buf, count, ppos, page, length);
out:
mutex_unlock(&sel_mutex);
if (new_value)
new_value = 1;
- inode = filep->f_dentry->d_inode;
- bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
+ inode = filep->f_path.dentry->d_inode;
+ bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
length = count;
out:
return length;
}
-static struct file_operations sel_bool_ops = {
+static const struct file_operations sel_bool_ops = {
.read = sel_read_bool,
.write = sel_write_bool,
};
return length;
}
-static struct file_operations sel_commit_bools_ops = {
+static const struct file_operations sel_commit_bools_ops = {
.write = sel_commit_bools_write,
};
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_u.fu_list);
- struct dentry * dentry = filp->f_dentry;
+ struct dentry * dentry = filp->f_path.dentry;
if (dentry->d_parent != de) {
continue;
isec->sid = sid;
isec->initialized = 1;
inode->i_fop = &sel_bool_ops;
- inode->i_ino = i + BOOL_INO_OFFSET;
+ inode->i_ino = i|SEL_BOOL_INO_OFFSET;
d_add(dentry, inode);
}
bool_num = num;
return ret;
}
-static struct file_operations sel_avc_cache_threshold_ops = {
+static const struct file_operations sel_avc_cache_threshold_ops = {
.read = sel_read_avc_cache_threshold,
.write = sel_write_avc_cache_threshold,
};
-static struct file_operations sel_avc_hash_stats_ops = {
+static const struct file_operations sel_avc_hash_stats_ops = {
.read = sel_read_avc_hash_stats,
};
return seq_open(file, &sel_avc_cache_stats_seq_ops);
}
-static struct file_operations sel_avc_cache_stats_ops = {
+static const struct file_operations sel_avc_cache_stats_ops = {
.open = sel_open_avc_cache_stats,
.read = seq_read,
.llseek = seq_lseek,
goto out;
}
inode->i_fop = files[i].ops;
+ inode->i_ino = ++sel_last_ino;
+ d_add(dentry, inode);
+ }
+out:
+ return ret;
+}
+
+static ssize_t sel_read_initcon(struct file * file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode *inode;
+ char *con;
+ u32 sid, len;
+ ssize_t ret;
+
+ inode = file->f_path.dentry->d_inode;
+ sid = inode->i_ino&SEL_INO_MASK;
+ ret = security_sid_to_context(sid, &con, &len);
+ if (ret < 0)
+ return ret;
+
+ ret = simple_read_from_buffer(buf, count, ppos, con, len);
+ kfree(con);
+ return ret;
+}
+
+static const struct file_operations sel_initcon_ops = {
+ .read = sel_read_initcon,
+};
+
+static int sel_make_initcon_files(struct dentry *dir)
+{
+ int i, ret = 0;
+
+ for (i = 1; i <= SECINITSID_NUM; i++) {
+ struct inode *inode;
+ struct dentry *dentry;
+ dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
+ if (!dentry) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
+ if (!inode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ inode->i_fop = &sel_initcon_ops;
+ inode->i_ino = i|SEL_INITCON_INO_OFFSET;
d_add(dentry, inode);
}
out:
}
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
+ inode->i_ino = ++sel_last_ino;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
d_add(dentry, inode);
/* bump link count on parent directory, too */
- dir->i_nlink++;
+ inc_nlink(dir);
out:
return ret;
}
[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);
ret = -ENOMEM;
goto err;
}
+ inode->i_ino = ++sel_last_ino;
isec = (struct inode_security_struct*)inode->i_security;
isec->sid = SECINITSID_DEVNULL;
isec->sclass = SECCLASS_CHR_FILE;
ret = sel_make_avc_files(dentry);
if (ret)
goto err;
+
+ dentry = d_alloc_name(sb->s_root, "initial_contexts");
+ if (!dentry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = sel_make_dir(root_inode, dentry);
+ if (ret)
+ goto err;
+
+ ret = sel_make_initcon_files(dentry);
+ if (ret)
+ goto err;
+
out:
return ret;
err:
goto out;
}
-static struct super_block *sel_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sel_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, sel_fill_super);
+ return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
}
static struct file_system_type sel_fs_type = {