summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 08:44:29 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 08:44:29 -0800
commitb47711bfbcd4eb77ca61ef0162487b20e023ae55 (patch)
treeb2a695dbd40f7ca2333664cf946ef34eda7b7dba
parent7556afa0e0e436cad4f560ee83e5fbd5dac9359a (diff)
parent2e08c0c1c3977a5ddc88887dd3af1b26c433e9d0 (diff)
downloadkernel-common-b47711bfbcd4eb77ca61ef0162487b20e023ae55.tar.gz
kernel-common-b47711bfbcd4eb77ca61ef0162487b20e023ae55.tar.bz2
kernel-common-b47711bfbcd4eb77ca61ef0162487b20e023ae55.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6: selinux: make mls_compute_sid always polyinstantiate security/selinux: constify function pointer tables and fields security: add a secctx_to_secid() hook security: call security_file_permission from rw_verify_area security: remove security_sb_post_mountroot hook Security: remove security.h include from mm.h Security: remove security_file_mmap hook sparse-warnings (NULL as 0). Security: add get, set, and cloning of superblock security information security/selinux: Add missing "space"
-rw-r--r--fs/compat.c4
-rw-r--r--fs/read_write.c63
-rw-r--r--fs/splice.c8
-rw-r--r--include/linux/mm.h3
-rw-r--r--include/linux/security.h59
-rw-r--r--init/do_mounts.c1
-rw-r--r--mm/mmap.c4
-rw-r--r--security/dummy.c36
-rw-r--r--security/keys/proc.c4
-rw-r--r--security/security.c31
-rw-r--r--security/selinux/hooks.c754
-rw-r--r--security/selinux/include/objsec.h1
-rw-r--r--security/selinux/selinuxfs.c2
-rw-r--r--security/selinux/ss/avtab.c2
-rw-r--r--security/selinux/ss/mls.c11
15 files changed, 642 insertions, 341 deletions
diff --git a/fs/compat.c b/fs/compat.c
index 15078ce4c04a..5216c3fd7517 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1104,10 +1104,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
if (ret < 0)
goto out;
- ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
- if (ret)
- goto out;
-
fnv = NULL;
if (type == READ) {
fn = file->f_op->read;
diff --git a/fs/read_write.c b/fs/read_write.c
index ea1f94cc722e..c4d3d17923f1 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -197,25 +197,27 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
{
struct inode *inode;
loff_t pos;
+ int retval = -EINVAL;
inode = file->f_path.dentry->d_inode;
if (unlikely((ssize_t) count < 0))
- goto Einval;
+ return retval;
pos = *ppos;
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
- goto Einval;
+ return retval;
if (unlikely(inode->i_flock && mandatory_lock(inode))) {
- int retval = locks_mandatory_area(
+ retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
inode, file, pos, count);
if (retval < 0)
return retval;
}
+ retval = security_file_permission(file,
+ read_write == READ ? MAY_READ : MAY_WRITE);
+ if (retval)
+ return retval;
return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
-
-Einval:
- return -EINVAL;
}
static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
@@ -267,18 +269,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
ret = rw_verify_area(READ, file, pos, count);
if (ret >= 0) {
count = ret;
- ret = security_file_permission (file, MAY_READ);
- if (!ret) {
- if (file->f_op->read)
- ret = file->f_op->read(file, buf, count, pos);
- else
- ret = do_sync_read(file, buf, count, pos);
- if (ret > 0) {
- fsnotify_access(file->f_path.dentry);
- add_rchar(current, ret);
- }
- inc_syscr(current);
+ if (file->f_op->read)
+ ret = file->f_op->read(file, buf, count, pos);
+ else
+ ret = do_sync_read(file, buf, count, pos);
+ if (ret > 0) {
+ fsnotify_access(file->f_path.dentry);
+ add_rchar(current, ret);
}
+ inc_syscr(current);
}
return ret;
@@ -325,18 +324,15 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
ret = rw_verify_area(WRITE, file, pos, count);
if (ret >= 0) {
count = ret;
- ret = security_file_permission (file, MAY_WRITE);
- if (!ret) {
- if (file->f_op->write)
- ret = file->f_op->write(file, buf, count, pos);
- else
- ret = do_sync_write(file, buf, count, pos);
- if (ret > 0) {
- fsnotify_modify(file->f_path.dentry);
- add_wchar(current, ret);
- }
- inc_syscw(current);
+ if (file->f_op->write)
+ ret = file->f_op->write(file, buf, count, pos);
+ else
+ ret = do_sync_write(file, buf, count, pos);
+ if (ret > 0) {
+ fsnotify_modify(file->f_path.dentry);
+ add_wchar(current, ret);
}
+ inc_syscw(current);
}
return ret;
@@ -603,9 +599,6 @@ static ssize_t do_readv_writev(int type, struct file *file,
ret = rw_verify_area(type, file, pos, tot_len);
if (ret < 0)
goto out;
- ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
- if (ret)
- goto out;
fnv = NULL;
if (type == READ) {
@@ -737,10 +730,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
goto fput_in;
count = retval;
- retval = security_file_permission (in_file, MAY_READ);
- if (retval)
- goto fput_in;
-
/*
* Get output file, and verify that it is ok..
*/
@@ -759,10 +748,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
goto fput_out;
count = retval;
- retval = security_file_permission (out_file, MAY_WRITE);
- if (retval)
- goto fput_out;
-
if (!max)
max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
diff --git a/fs/splice.c b/fs/splice.c
index 6bdcb6107bc3..56b802bfbfa4 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -908,10 +908,6 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
if (unlikely(ret < 0))
return ret;
- ret = security_file_permission(out, MAY_WRITE);
- if (unlikely(ret < 0))
- return ret;
-
return out->f_op->splice_write(pipe, out, ppos, len, flags);
}
@@ -934,10 +930,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
if (unlikely(ret < 0))
return ret;
- ret = security_file_permission(in, MAY_READ);
- if (unlikely(ret < 0))
- return ret;
-
return in->f_op->splice_read(in, ppos, pipe, len, flags);
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 1b7b95c67aca..1897ca223eca 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -12,7 +12,6 @@
#include <linux/prio_tree.h>
#include <linux/debug_locks.h>
#include <linux/mm_types.h>
-#include <linux/security.h>
struct mempolicy;
struct anon_vma;
@@ -34,6 +33,8 @@ extern int sysctl_legacy_va_layout;
#define sysctl_legacy_va_layout 0
#endif
+extern unsigned long mmap_min_addr;
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
diff --git a/include/linux/security.h b/include/linux/security.h
index ac050830a873..d24974262dc6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -34,6 +34,12 @@
#include <linux/xfrm.h>
#include <net/flow.h>
+/* only a char in selinux superblock security struct flags */
+#define FSCONTEXT_MNT 0x01
+#define CONTEXT_MNT 0x02
+#define ROOTCONTEXT_MNT 0x04
+#define DEFCONTEXT_MNT 0x08
+
/*
* Bounding set
*/
@@ -243,9 +249,6 @@ struct request_sock;
* @mnt contains the mounted file system.
* @flags contains the new filesystem flags.
* @data contains the filesystem-specific data.
- * @sb_post_mountroot:
- * Update the security module's state when the root filesystem is mounted.
- * This hook is only called if the mount was successful.
* @sb_post_addmount:
* Update the security module's state when a filesystem is mounted.
* This hook is called any time a mount is successfully grafetd to
@@ -261,6 +264,22 @@ struct request_sock;
* Update module state after a successful pivot.
* @old_nd contains the nameidata structure for the old root.
* @new_nd contains the nameidata structure for the new root.
+ * @sb_get_mnt_opts:
+ * Get the security relevant mount options used for a superblock
+ * @sb the superblock to get security mount options from
+ * @mount_options array for pointers to mount options
+ * @mount_flags array of ints specifying what each mount options is
+ * @num_opts number of options in the arrays
+ * @sb_set_mnt_opts:
+ * Set the security relevant mount options used for a superblock
+ * @sb the superblock to set security mount options for
+ * @mount_options array for pointers to mount options
+ * @mount_flags array of ints specifying what each mount options is
+ * @num_opts number of options in the arrays
+ * @sb_clone_mnt_opts:
+ * Copy all security options from a given superblock to another
+ * @oldsb old superblock which contain information to clone
+ * @newsb new superblock which needs filled in
*
* Security hooks for inode operations.
*
@@ -1183,6 +1202,10 @@ struct request_sock;
* Convert secid to security context.
* @secid contains the security ID.
* @secdata contains the pointer that stores the converted security context.
+ * @secctx_to_secid:
+ * Convert security context to secid.
+ * @secid contains the pointer to the generated security ID.
+ * @secdata contains the security context.
*
* @release_secctx:
* Release the security context.
@@ -1235,13 +1258,19 @@ struct security_operations {
void (*sb_umount_busy) (struct vfsmount * mnt);
void (*sb_post_remount) (struct vfsmount * mnt,
unsigned long flags, void *data);
- void (*sb_post_mountroot) (void);
void (*sb_post_addmount) (struct vfsmount * mnt,
struct nameidata * mountpoint_nd);
int (*sb_pivotroot) (struct nameidata * old_nd,
struct nameidata * new_nd);
void (*sb_post_pivotroot) (struct nameidata * old_nd,
struct nameidata * new_nd);
+ int (*sb_get_mnt_opts) (const struct super_block *sb,
+ char ***mount_options, int **flags,
+ int *num_opts);
+ int (*sb_set_mnt_opts) (struct super_block *sb, char **mount_options,
+ int *flags, int num_opts);
+ void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
+ struct super_block *newsb);
int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
@@ -1371,6 +1400,7 @@ struct security_operations {
int (*getprocattr)(struct task_struct *p, char *name, char **value);
int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size);
int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
+ int (*secctx_to_secid)(char *secdata, u32 seclen, u32 *secid);
void (*release_secctx)(char *secdata, u32 seclen);
#ifdef CONFIG_SECURITY_NETWORK
@@ -1495,10 +1525,16 @@ int security_sb_umount(struct vfsmount *mnt, int flags);
void security_sb_umount_close(struct vfsmount *mnt);
void security_sb_umount_busy(struct vfsmount *mnt);
void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data);
-void security_sb_post_mountroot(void);
void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd);
int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
+int security_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
+ int **flags, int *num_opts);
+int security_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
+ int *flags, int num_opts);
+void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+ struct super_block *newsb);
+
int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir,
@@ -1603,6 +1639,7 @@ int security_setprocattr(struct task_struct *p, char *name, void *value, size_t
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_netlink_recv(struct sk_buff *skb, int cap);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
#else /* CONFIG_SECURITY */
@@ -1777,9 +1814,6 @@ static inline void security_sb_post_remount (struct vfsmount *mnt,
unsigned long flags, void *data)
{ }
-static inline void security_sb_post_mountroot (void)
-{ }
-
static inline void security_sb_post_addmount (struct vfsmount *mnt,
struct nameidata *mountpoint_nd)
{ }
@@ -2266,7 +2300,7 @@ static inline struct dentry *securityfs_create_file(const char *name,
mode_t mode,
struct dentry *parent,
void *data,
- struct file_operations *fops)
+ const struct file_operations *fops)
{
return ERR_PTR(-ENODEV);
}
@@ -2280,6 +2314,13 @@ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *secle
return -EOPNOTSUPP;
}
+static inline int security_secctx_to_secid(char *secdata,
+ u32 seclen,
+ u32 *secid)
+{
+ return -EOPNOTSUPP;
+}
+
static inline void security_release_secctx(char *secdata, u32 seclen)
{
}
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 2ae5b8462399..1161dfd7b0d3 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -378,6 +378,5 @@ void __init prepare_namespace(void)
out:
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
- security_sb_post_mountroot();
}
diff --git a/mm/mmap.c b/mm/mmap.c
index 15678aa6ec73..bfa389fc6ded 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1620,7 +1620,7 @@ static inline int expand_downwards(struct vm_area_struct *vma,
return -ENOMEM;
address &= PAGE_MASK;
- error = security_file_mmap(0, 0, 0, 0, address, 1);
+ error = security_file_mmap(NULL, 0, 0, 0, address, 1);
if (error)
return error;
@@ -1941,7 +1941,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
if (is_hugepage_only_range(mm, addr, len))
return -EINVAL;
- error = security_file_mmap(0, 0, 0, 0, addr, 1);
+ error = security_file_mmap(NULL, 0, 0, 0, addr, 1);
if (error)
return error;
diff --git a/security/dummy.c b/security/dummy.c
index 3ccfbbe973b6..48d4b0a52737 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -225,22 +225,40 @@ static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
}
-static void dummy_sb_post_mountroot (void)
+static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
{
return;
}
-static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
+static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+ return 0;
+}
+
+static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
{
return;
}
-static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+static int dummy_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
+ int **flags, int *num_opts)
{
+ *mount_options = NULL;
+ *flags = NULL;
+ *num_opts = 0;
return 0;
}
-static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+static int dummy_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
+ int *flags, int num_opts)
+{
+ if (unlikely(num_opts))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
+ struct super_block *newsb)
{
return;
}
@@ -928,6 +946,11 @@ static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
return -EOPNOTSUPP;
}
+static int dummy_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+ return -EOPNOTSUPP;
+}
+
static void dummy_release_secctx(char *secdata, u32 seclen)
{
}
@@ -994,10 +1017,12 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, sb_umount_close);
set_to_dummy_if_null(ops, sb_umount_busy);
set_to_dummy_if_null(ops, sb_post_remount);
- set_to_dummy_if_null(ops, sb_post_mountroot);
set_to_dummy_if_null(ops, sb_post_addmount);
set_to_dummy_if_null(ops, sb_pivotroot);
set_to_dummy_if_null(ops, sb_post_pivotroot);
+ set_to_dummy_if_null(ops, sb_get_mnt_opts);
+ set_to_dummy_if_null(ops, sb_set_mnt_opts);
+ set_to_dummy_if_null(ops, sb_clone_mnt_opts);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
set_to_dummy_if_null(ops, inode_init_security);
@@ -1086,6 +1111,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, getprocattr);
set_to_dummy_if_null(ops, setprocattr);
set_to_dummy_if_null(ops, secid_to_secctx);
+ set_to_dummy_if_null(ops, secctx_to_secid);
set_to_dummy_if_null(ops, release_secctx);
#ifdef CONFIG_SECURITY_NETWORK
set_to_dummy_if_null(ops, unix_stream_connect);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 3e0d0a6e224f..694126003ed3 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -26,7 +26,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_keys_stop(struct seq_file *p, void *v);
static int proc_keys_show(struct seq_file *m, void *v);
-static struct seq_operations proc_keys_ops = {
+static const struct seq_operations proc_keys_ops = {
.start = proc_keys_start,
.next = proc_keys_next,
.stop = proc_keys_stop,
@@ -47,7 +47,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_key_users_stop(struct seq_file *p, void *v);
static int proc_key_users_show(struct seq_file *m, void *v);
-static struct seq_operations proc_key_users_ops = {
+static const struct seq_operations proc_key_users_ops = {
.start = proc_key_users_start,
.next = proc_key_users_next,
.stop = proc_key_users_stop,
diff --git a/security/security.c b/security/security.c
index 0e1f1f124368..ca475ca206e4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -288,11 +288,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d
security_ops->sb_post_remount(mnt, flags, data);
}
-void security_sb_post_mountroot(void)
-{
- security_ops->sb_post_mountroot();
-}
-
void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd)
{
security_ops->sb_post_addmount(mnt, mountpoint_nd);
@@ -308,6 +303,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_
security_ops->sb_post_pivotroot(old_nd, new_nd);
}
+int security_sb_get_mnt_opts(const struct super_block *sb,
+ char ***mount_options,
+ int **flags, int *num_opts)
+{
+ return security_ops->sb_get_mnt_opts(sb, mount_options, flags, num_opts);
+}
+
+int security_sb_set_mnt_opts(struct super_block *sb,
+ char **mount_options,
+ int *flags, int num_opts)
+{
+ return security_ops->sb_set_mnt_opts(sb, mount_options, flags, num_opts);
+}
+
+void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+ struct super_block *newsb)
+{
+ security_ops->sb_clone_mnt_opts(oldsb, newsb);
+}
+
int security_inode_alloc(struct inode *inode)
{
inode->i_security = NULL;
@@ -816,6 +831,12 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
}
EXPORT_SYMBOL(security_secid_to_secctx);
+int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+ return security_ops->secctx_to_secid(secdata, seclen, secid);
+}
+EXPORT_SYMBOL(security_secctx_to_secid);
+
void security_release_secctx(char *secdata, u32 seclen)
{
return security_ops->release_secctx(secdata, seclen);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9f3124b08867..0396354fff95 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -82,6 +82,8 @@
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+#define NUM_SEL_MNT_OPTS 4
+
extern unsigned int policydb_loaded_version;
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern int selinux_compat_net;
@@ -321,8 +323,8 @@ enum {
Opt_error = -1,
Opt_context = 1,
Opt_fscontext = 2,
- Opt_defcontext = 4,
- Opt_rootcontext = 8,
+ Opt_defcontext = 3,
+ Opt_rootcontext = 4,
};
static match_table_t tokens = {
@@ -366,150 +368,317 @@ static int may_context_mount_inode_relabel(u32 sid,
return rc;
}
-static int try_context_mount(struct super_block *sb, void *data)
+static int sb_finish_set_opts(struct super_block *sb)
{
- char *context = NULL, *defcontext = NULL;
- char *fscontext = NULL, *rootcontext = NULL;
- const char *name;
- u32 sid;
- int alloc = 0, rc = 0, seen = 0;
- struct task_security_struct *tsec = current->security;
struct superblock_security_struct *sbsec = sb->s_security;
+ struct dentry *root = sb->s_root;
+ struct inode *root_inode = root->d_inode;
+ int rc = 0;
- if (!data)
- goto out;
+ if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
+ /* Make sure that the xattr handler exists and that no
+ error other than -ENODATA is returned by getxattr on
+ the root directory. -ENODATA is ok, as this may be
+ the first boot of the SELinux kernel before we have
+ assigned xattr values to the filesystem. */
+ if (!root_inode->i_op->getxattr) {
+ printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
+ "xattr support\n", sb->s_id, sb->s_type->name);
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+ rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
+ if (rc < 0 && rc != -ENODATA) {
+ if (rc == -EOPNOTSUPP)
+ printk(KERN_WARNING "SELinux: (dev %s, type "
+ "%s) has no security xattr handler\n",
+ sb->s_id, sb->s_type->name);
+ else
+ printk(KERN_WARNING "SELinux: (dev %s, type "
+ "%s) getxattr errno %d\n", sb->s_id,
+ sb->s_type->name, -rc);
+ goto out;
+ }
+ }
- name = sb->s_type->name;
+ sbsec->initialized = 1;
- if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
+ if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+ printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
+ sb->s_id, sb->s_type->name);
+ else
+ printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
+ sb->s_id, sb->s_type->name,
+ labeling_behaviors[sbsec->behavior-1]);
- /* NFS we understand. */
- if (!strcmp(name, "nfs")) {
- struct nfs_mount_data *d = data;
+ /* Initialize the root inode. */
+ rc = inode_doinit_with_dentry(root_inode, root);
- if (d->version < NFS_MOUNT_VERSION)
- goto out;
+ /* Initialize any other inodes associated with the superblock, e.g.
+ inodes created prior to initial policy load or inodes created
+ during get_sb by a pseudo filesystem that directly
+ populates itself. */
+ spin_lock(&sbsec->isec_lock);
+next_inode:
+ if (!list_empty(&sbsec->isec_head)) {
+ struct inode_security_struct *isec =
+ list_entry(sbsec->isec_head.next,
+ struct inode_security_struct, list);
+ struct inode *inode = isec->inode;
+ spin_unlock(&sbsec->isec_lock);
+ inode = igrab(inode);
+ if (inode) {
+ if (!IS_PRIVATE(inode))
+ inode_doinit(inode);
+ iput(inode);
+ }
+ spin_lock(&sbsec->isec_lock);
+ list_del_init(&isec->list);
+ goto next_inode;
+ }
+ spin_unlock(&sbsec->isec_lock);
+out:
+ return rc;
+}
- if (d->context[0]) {
- context = d->context;
- seen |= Opt_context;
- }
- } else
- goto out;
+/*
+ * This function should allow an FS to ask what it's mount security
+ * options were so it can use those later for submounts, displaying
+ * mount options, or whatever.
+ */
+static int selinux_get_mnt_opts(const struct super_block *sb,
+ char ***mount_options, int **mnt_opts_flags,
+ int *num_opts)
+{
+ int rc = 0, i;
+ struct superblock_security_struct *sbsec = sb->s_security;
+ char *context = NULL;
+ u32 len;
+ char tmp;
- } else {
- /* Standard string-based options. */
- char *p, *options = data;
+ *num_opts = 0;
+ *mount_options = NULL;
+ *mnt_opts_flags = NULL;
- while ((p = strsep(&options, "|")) != NULL) {
- int token;
- substring_t args[MAX_OPT_ARGS];
+ if (!sbsec->initialized)
+ return -EINVAL;
- if (!*p)
- continue;
+ if (!ss_initialized)
+ return -EINVAL;
- token = match_token(p, tokens, args);
+ /*
+ * if we ever use sbsec flags for anything other than tracking mount
+ * settings this is going to need a mask
+ */
+ tmp = sbsec->flags;
+ /* count the number of mount options for this sb */
+ for (i = 0; i < 8; i++) {
+ if (tmp & 0x01)
+ (*num_opts)++;
+ tmp >>= 1;
+ }
- switch (token) {
- case Opt_context:
- if (seen & (Opt_context|Opt_defcontext)) {
- rc = -EINVAL;
- printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
- goto out_free;
- }
- context = match_strdup(&args[0]);
- if (!context) {
- rc = -ENOMEM;
- goto out_free;
- }
- if (!alloc)
- alloc = 1;
- seen |= Opt_context;
- break;
+ *mount_options = kcalloc(*num_opts, sizeof(char *), GFP_ATOMIC);
+ if (!*mount_options) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
- case Opt_fscontext:
- if (seen & Opt_fscontext) {
- rc = -EINVAL;
- printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
- goto out_free;
- }
- fscontext = match_strdup(&args[0]);
- if (!fscontext) {
- rc = -ENOMEM;
- goto out_free;
- }
- if (!alloc)
- alloc = 1;
- seen |= Opt_fscontext;
- break;
+ *mnt_opts_flags = kcalloc(*num_opts, sizeof(int), GFP_ATOMIC);
+ if (!*mnt_opts_flags) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
- case Opt_rootcontext:
- if (seen & Opt_rootcontext) {
- rc = -EINVAL;
- printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
- goto out_free;
- }
- rootcontext = match_strdup(&args[0]);
- if (!rootcontext) {
- rc = -ENOMEM;
- goto out_free;
- }
- if (!alloc)
- alloc = 1;
- seen |= Opt_rootcontext;
- break;
+ i = 0;
+ if (sbsec->flags & FSCONTEXT_MNT) {
+ rc = security_sid_to_context(sbsec->sid, &context, &len);
+ if (rc)
+ goto out_free;
+ (*mount_options)[i] = context;
+ (*mnt_opts_flags)[i++] = FSCONTEXT_MNT;
+ }
+ if (sbsec->flags & CONTEXT_MNT) {
+ rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
+ if (rc)
+ goto out_free;
+ (*mount_options)[i] = context;
+ (*mnt_opts_flags)[i++] = CONTEXT_MNT;
+ }
+ if (sbsec->flags & DEFCONTEXT_MNT) {
+ rc = security_sid_to_context(sbsec->def_sid, &context, &len);
+ if (rc)
+ goto out_free;
+ (*mount_options)[i] = context;
+ (*mnt_opts_flags)[i++] = DEFCONTEXT_MNT;
+ }
+ if (sbsec->flags & ROOTCONTEXT_MNT) {
+ struct inode *root = sbsec->sb->s_root->d_inode;
+ struct inode_security_struct *isec = root->i_security;
- case Opt_defcontext:
- if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
- rc = -EINVAL;
- printk(KERN_WARNING "SELinux: "
- "defcontext option is invalid "
- "for this filesystem type\n");
- goto out_free;
- }
- if (seen & (Opt_context|Opt_defcontext)) {
- rc = -EINVAL;
- printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
- goto out_free;
- }
- defcontext = match_strdup(&args[0]);
- if (!defcontext) {
- rc = -ENOMEM;
- goto out_free;
- }
- if (!alloc)
- alloc = 1;
- seen |= Opt_defcontext;
- break;
+ rc = security_sid_to_context(isec->sid, &context, &len);
+ if (rc)
+ goto out_free;
+ (*mount_options)[i] = context;
+ (*mnt_opts_flags)[i++] = ROOTCONTEXT_MNT;
+ }
- default:
- rc = -EINVAL;
- printk(KERN_WARNING "SELinux: unknown mount "
- "option\n");
- goto out_free;
+ BUG_ON(i != *num_opts);
- }
- }
- }
+ return 0;
+
+out_free:
+ /* don't leak context string if security_sid_to_context had an error */
+ if (*mount_options && i)
+ for (; i > 0; i--)
+ kfree((*mount_options)[i-1]);
+ kfree(*mount_options);
+ *mount_options = NULL;
+ kfree(*mnt_opts_flags);
+ *mnt_opts_flags = NULL;
+ *num_opts = 0;
+ return rc;
+}
+
+static int bad_option(struct superblock_security_struct *sbsec, char flag,
+ u32 old_sid, u32 new_sid)
+{
+ /* check if the old mount command had the same options */
+ if (sbsec->initialized)
+ if (!(sbsec->flags & flag) ||
+ (old_sid != new_sid))
+ return 1;
+
+ /* check if we were passed the same options twice,
+ * aka someone passed context=a,context=b
+ */
+ if (!sbsec->initialized)
+ if (sbsec->flags & flag)
+ return 1;
+ return 0;
+}
+/*
+ * Allow filesystems with binary mount data to explicitly set mount point
+ * labeling information.
+ */
+int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
+ int *flags, int num_opts)
+{
+ int rc = 0, i;
+ struct task_security_struct *tsec = current->security;
+ struct superblock_security_struct *sbsec = sb->s_security;
+ const char *name = sb->s_type->name;
+ struct inode *inode = sbsec->sb->s_root->d_inode;
+ struct inode_security_struct *root_isec = inode->i_security;
+ u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
+ u32 defcontext_sid = 0;
- if (!seen)
+ mutex_lock(&sbsec->lock);
+
+ if (!ss_initialized) {
+ if (!num_opts) {
+ /* Defer initialization until selinux_complete_init,
+ after the initial policy is loaded and the security
+ server is ready to handle calls. */
+ spin_lock(&sb_security_lock);
+ if (list_empty(&sbsec->list))
+ list_add(&sbsec->list, &superblock_security_head);
+ spin_unlock(&sb_security_lock);
+ goto out;
+ }
+ rc = -EINVAL;
+ printk(KERN_WARNING "Unable to set superblock options before "
+ "the security server is initialized\n");
goto out;
+ }
- /* sets the context of the superblock for the fs being mounted. */
- if (fscontext) {
- rc = security_context_to_sid(fscontext, strlen(fscontext), &sid);
+ /*
+ * parse the mount options, check if they are valid sids.
+ * also check if someone is trying to mount the same sb more
+ * than once with different security options.
+ */
+ for (i = 0; i < num_opts; i++) {
+ u32 sid;
+ rc = security_context_to_sid(mount_options[i],
+ strlen(mount_options[i]), &sid);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
- fscontext, sb->s_id, name, rc);
- goto out_free;
+ mount_options[i], sb->s_id, name, rc);
+ goto out;
}
+ switch (flags[i]) {
+ case FSCONTEXT_MNT:
+ fscontext_sid = sid;
+
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+ fscontext_sid))
+ goto out_double_mount;
+
+ sbsec->flags |= FSCONTEXT_MNT;
+ break;
+ case CONTEXT_MNT:
+ context_sid = sid;
+
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+ context_sid))
+ goto out_double_mount;
+
+ sbsec->flags |= CONTEXT_MNT;
+ break;
+ case ROOTCONTEXT_MNT:
+ rootcontext_sid = sid;
+
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+ rootcontext_sid))
+ goto out_double_mount;
+
+ sbsec->flags |= ROOTCONTEXT_MNT;
+
+ break;
+ case DEFCONTEXT_MNT:
+ defcontext_sid = sid;
+
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+ defcontext_sid))
+ goto out_double_mount;
+
+ sbsec->flags |= DEFCONTEXT_MNT;
+
+ break;
+ default:
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (sbsec->initialized) {
+ /* previously mounted with options, but not on this attempt? */
+ if (sbsec->flags && !num_opts)
+ goto out_double_mount;
+ rc = 0;
+ goto out;
+ }
+
+ if (strcmp(sb->s_type->name, "proc") == 0)
+ sbsec->proc = 1;
+
+ /* Determine the labeling behavior to use for this filesystem type. */
+ rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+ if (rc) {
+ printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
+ __FUNCTION__, sb->s_type->name, rc);
+ goto out;
+ }
+
+ /* sets the context of the superblock for the fs being mounted. */
+ if (fscontext_sid) {
- rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+ rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
if (rc)
- goto out_free;
+ goto out;
- sbsec->sid = sid;
+ sbsec->sid = fscontext_sid;
}
/*
@@ -517,182 +686,250 @@ static int try_context_mount(struct super_block *sb, void *data)
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
- if (context) {
- rc = security_context_to_sid(context, strlen(context), &sid);
- if (rc) {
- printk(KERN_WARNING "SELinux: security_context_to_sid"
- "(%s) failed for (dev %s, type %s) errno=%d\n",
- context, sb->s_id, name, rc);
- goto out_free;
- }
-
- if (!fscontext) {
- rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+ if (context_sid) {
+ if (!fscontext_sid) {
+ rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
if (rc)
- goto out_free;
- sbsec->sid = sid;
+ goto out;
+ sbsec->sid = context_sid;
} else {
- rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+ rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
if (rc)
- goto out_free;
+ goto out;
}
- sbsec->mntpoint_sid = sid;
+ if (!rootcontext_sid)
+ rootcontext_sid = context_sid;
+ sbsec->mntpoint_sid = context_sid;
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
}
- if (rootcontext) {
- struct inode *inode = sb->s_root->d_inode;
- struct inode_security_struct *isec = inode->i_security;
- rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid);
- if (rc) {
- printk(KERN_WARNING "SELinux: security_context_to_sid"
- "(%s) failed for (dev %s, type %s) errno=%d\n",
- rootcontext, sb->s_id, name, rc);
- goto out_free;
- }
-
- rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+ if (rootcontext_sid) {
+ rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
if (rc)
- goto out_free;
+ goto out;
- isec->sid = sid;
- isec->initialized = 1;
+ root_isec->sid = rootcontext_sid;
+ root_isec->initialized = 1;
}
- if (defcontext) {
- rc = security_context_to_sid(defcontext, strlen(defcontext), &sid);
- if (rc) {
- printk(KERN_WARNING "SELinux: security_context_to_sid"
- "(%s) failed for (dev %s, type %s) errno=%d\n",
- defcontext, sb->s_id, name, rc);
- goto out_free;
+ if (defcontext_sid) {
+ if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
+ rc = -EINVAL;
+ printk(KERN_WARNING "SELinux: defcontext option is "
+ "invalid for this filesystem type\n");
+ goto out;
}
- if (sid == sbsec->def_sid)
- goto out_free;
-
- rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
- if (rc)
- goto out_free;
+ if (defcontext_sid != sbsec->def_sid) {
+ rc = may_context_mount_inode_relabel(defcontext_sid,
+ sbsec, tsec);
+ if (rc)
+ goto out;
+ }
- sbsec->def_sid = sid;
+ sbsec->def_sid = defcontext_sid;
}
-out_free:
- if (alloc) {
- kfree(context);
- kfree(defcontext);
- kfree(fscontext);
- kfree(rootcontext);
- }
+ rc = sb_finish_set_opts(sb);
out:
+ mutex_unlock(&sbsec->lock);
return rc;
+out_double_mount:
+ rc = -EINVAL;
+ printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
+ "security settings for (dev %s, type %s)\n", sb->s_id, name);
+ goto out;
}
-static int superblock_doinit(struct super_block *sb, void *data)
+static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
+ struct super_block *newsb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
- struct dentry *root = sb->s_root;
- struct inode *inode = root->d_inode;
- int rc = 0;
+ const struct superblock_security_struct *oldsbsec = oldsb->s_security;
+ struct superblock_security_struct *newsbsec = newsb->s_security;
- mutex_lock(&sbsec->lock);
- if (sbsec->initialized)
- goto out;
+ int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
+ int set_context = (oldsbsec->flags & CONTEXT_MNT);
+ int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
- if (!ss_initialized) {
- /* Defer initialization until selinux_complete_init,
- after the initial policy is loaded and the security
- server is ready to handle calls. */
- spin_lock(&sb_security_lock);
- if (list_empty(&sbsec->list))
- list_add(&sbsec->list, &superblock_security_head);
- spin_unlock(&sb_security_lock);
- goto out;
+ /* we can't error, we can't save the info, this shouldn't get called
+ * this early in the boot process. */
+ BUG_ON(!ss_initialized);
+
+ /* this might go away sometime down the line if there is a new user
+ * of clone, but for now, nfs better not get here... */
+ BUG_ON(newsbsec->initialized);
+
+ /* how can we clone if the old one wasn't set up?? */
+ BUG_ON(!oldsbsec->initialized);
+
+ mutex_lock(&newsbsec->lock);
+
+ newsbsec->flags = oldsbsec->flags;
+
+ newsbsec->sid = oldsbsec->sid;
+ newsbsec->def_sid = oldsbsec->def_sid;
+ newsbsec->behavior = oldsbsec->behavior;
+
+ if (set_context) {
+ u32 sid = oldsbsec->mntpoint_sid;
+
+ if (!set_fscontext)
+ newsbsec->sid = sid;
+ if (!set_rootcontext) {
+ struct inode *newinode = newsb->s_root->d_inode;
+ struct inode_security_struct *newisec = newinode->i_security;
+ newisec->sid = sid;
+ }
+ newsbsec->mntpoint_sid = sid;
}
+ if (set_rootcontext) {
+ const struct inode *oldinode = oldsb->s_root->d_inode;
+ const struct inode_security_struct *oldisec = oldinode->i_security;
+ struct inode *newinode = newsb->s_root->d_inode;
+ struct inode_security_struct *newisec = newinode->i_security;
- /* Determine the labeling behavior to use for this filesystem type. */
- rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
- if (rc) {
- printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
- __FUNCTION__, sb->s_type->name, rc);
- goto out;
+ newisec->sid = oldisec->sid;
}
- rc = try_context_mount(sb, data);
- if (rc)
+ sb_finish_set_opts(newsb);
+ mutex_unlock(&newsbsec->lock);
+}
+
+/*
+ * string mount options parsing and call set the sbsec
+ */
+static int superblock_doinit(struct super_block *sb, void *data)
+{
+ char *context = NULL, *defcontext = NULL;
+ char *fscontext = NULL, *rootcontext = NULL;
+ int rc = 0;
+ char *p, *options = data;
+ /* selinux only know about a fixed number of mount options */
+ char *mnt_opts[NUM_SEL_MNT_OPTS];
+ int mnt_opts_flags[NUM_SEL_MNT_OPTS], num_mnt_opts = 0;
+
+ if (!data)
goto out;
- if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
- /* Make sure that the xattr handler exists and that no
- error other than -ENODATA is returned by getxattr on
- the root directory. -ENODATA is ok, as this may be
- the first boot of the SELinux kernel before we have
- assigned xattr values to the filesystem. */
- if (!inode->i_op->getxattr) {
- printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
- "xattr support\n", sb->s_id, sb->s_type->name);
- rc = -EOPNOTSUPP;
- goto out;
- }
- rc = inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
- if (rc < 0 && rc != -ENODATA) {
- if (rc == -EOPNOTSUPP)
- printk(KERN_WARNING "SELinux: (dev %s, type "
- "%s) has no security xattr handler\n",
- sb->s_id, sb->s_type->name);
- else
- printk(KERN_WARNING "SELinux: (dev %s, type "
- "%s) getxattr errno %d\n", sb->s_id,
- sb->s_type->name, -rc);
+ /* with the nfs patch this will become a goto out; */
+ if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
+ const char *name = sb->s_type->name;
+ /* NFS we understand. */
+ if (!strcmp(name, "nfs")) {
+ struct nfs_mount_data *d = data;
+
+ if (d->version != NFS_MOUNT_VERSION)
+ goto out;
+
+ if (d->context[0]) {
+ context = kstrdup(d->context, GFP_KERNEL);
+ if (!context) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+ goto build_flags;
+ } else
goto out;
- }
}
- if (strcmp(sb->s_type->name, "proc") == 0)
- sbsec->proc = 1;
+ /* Standard string-based options. */
+ while ((p = strsep(&options, "|")) != NULL) {
+ int token;
+ substring_t args[MAX_OPT_ARGS];
- sbsec->initialized = 1;
+ if (!*p)
+ continue;
- if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) {
- printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
- sb->s_id, sb->s_type->name);
- }
- else {
- printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
- sb->s_id, sb->s_type->name,
- labeling_behaviors[sbsec->behavior-1]);
- }
+ token = match_token(p, tokens, args);
- /* Initialize the root inode. */
- rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root);
+ switch (token) {
+ case Opt_context:
+ if (context || defcontext) {
+ rc = -EINVAL;
+ printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+ goto out_err;
+ }
+ context = match_strdup(&args[0]);
+ if (!context) {
+ rc = -ENOMEM;
+ goto out_err;
+ }
+ break;
+
+ case Opt_fscontext:
+ if (fscontext) {
+ rc = -EINVAL;
+ printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+ goto out_err;
+ }
+ fscontext = match_strdup(&args[0]);
+ if (!fscontext) {
+ rc = -ENOMEM;
+ goto out_err;
+ }
+ break;
+
+ case Opt_rootcontext:
+ if (rootcontext) {
+ rc = -EINVAL;
+ printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+ goto out_err;
+ }
+ rootcontext = match_strdup(&args[0]);
+ if (!rootcontext) {
+ rc = -ENOMEM;
+ goto out_err;
+ }
+ break;
+
+ case Opt_defcontext:
+ if (context || defcontext) {
+ rc = -EINVAL;
+ printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
+ goto out_err;
+ }
+ defcontext = match_strdup(&args[0]);
+ if (!defcontext) {
+ rc = -ENOMEM;
+ goto out_err;
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ printk(KERN_WARNING "SELinux: unknown mount option\n");
+ goto out_err;
- /* Initialize any other inodes associated with the superblock, e.g.
- inodes created prior to initial policy load or inodes created
- during get_sb by a pseudo filesystem that directly
- populates itself. */
- spin_lock(&sbsec->isec_lock);
-next_inode:
- if (!list_empty(&sbsec->isec_head)) {
- struct inode_security_struct *isec =
- list_entry(sbsec->isec_head.next,
- struct inode_security_struct, list);
- struct inode *inode = isec->inode;
- spin_unlock(&sbsec->isec_lock);
- inode = igrab(inode);
- if (inode) {
- if (!IS_PRIVATE (inode))
- inode_doinit(inode);
- iput(inode);
}
- spin_lock(&sbsec->isec_lock);
- list_del_init(&isec->list);
- goto next_inode;
}
- spin_unlock(&sbsec->isec_lock);
+
+build_flags:
+ if (fscontext) {
+ mnt_opts[num_mnt_opts] = fscontext;
+ mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
+ }
+ if (context) {
+ mnt_opts[num_mnt_opts] = context;
+ mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
+ }
+ if (rootcontext) {
+ mnt_opts[num_mnt_opts] = rootcontext;
+ mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
+ }
+ if (defcontext) {
+ mnt_opts[num_mnt_opts] = defcontext;
+ mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
+ }
+
out:
- mutex_unlock(&sbsec->lock);
+ rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts);
+out_err:
+ kfree(context);
+ kfree(defcontext);
+ kfree(fscontext);
+ kfree(rootcontext);
return rc;
}
@@ -4710,6 +4947,11 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
return security_sid_to_context(secid, secdata, seclen);
}
+static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+{
+ return security_context_to_sid(secdata, seclen, secid);
+}
+
static void selinux_release_secctx(char *secdata, u32 seclen)
{
kfree(secdata);
@@ -4800,6 +5042,9 @@ static struct security_operations selinux_ops = {
.sb_statfs = selinux_sb_statfs,
.sb_mount = selinux_mount,
.sb_umount = selinux_umount,
+ .sb_get_mnt_opts = selinux_get_mnt_opts,
+ .sb_set_mnt_opts = selinux_set_mnt_opts,
+ .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
.inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security,
@@ -4898,6 +5143,7 @@ static struct security_operations selinux_ops = {
.setprocattr = selinux_setprocattr,
.secid_to_secctx = selinux_secid_to_secctx,
+ .secctx_to_secid = selinux_secctx_to_secid,
.release_secctx = selinux_release_secctx,
.unix_stream_connect = selinux_socket_unix_stream_connect,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 642a9fd319ad..4138a80f8e27 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -65,6 +65,7 @@ struct superblock_security_struct {
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
unsigned int behavior; /* labeling behavior */
unsigned char initialized; /* initialization flag */
+ unsigned char flags; /* which mount options were specified */
unsigned char proc; /* proc fs */
struct mutex lock;
struct list_head isec_head;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2fa483f26113..397fd4955fe1 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1222,7 +1222,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
{ }
-static struct seq_operations sel_avc_cache_stats_seq_ops = {
+static const struct seq_operations sel_avc_cache_stats_seq_ops = {
.start = sel_avc_stats_seq_start,
.next = sel_avc_stats_seq_next,
.show = sel_avc_stats_seq_show,
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 9e70a160d7da..cd10e27fc9e6 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -280,7 +280,7 @@ int avtab_alloc(struct avtab *h, u32 nrules)
h->nel = 0;
h->nslot = nslot;
h->mask = mask;
- printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated."
+ printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. "
"Num of rules:%d\n", h->nslot, nrules);
return 0;
}
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index fb5d70a6628d..3bbcb5369af9 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -537,15 +537,8 @@ int mls_compute_sid(struct context *scontext,
/* Use the process effective MLS attributes. */
return mls_context_cpy_low(newcontext, scontext);
case AVTAB_MEMBER:
- /* Only polyinstantiate the MLS attributes if
- the type is being polyinstantiated */
- if (newcontext->type != tcontext->type) {
- /* Use the process effective MLS attributes. */
- return mls_context_cpy_low(newcontext, scontext);
- } else {
- /* Use the related object MLS attributes. */
- return mls_context_cpy(newcontext, tcontext);
- }
+ /* Use the process effective MLS attributes. */
+ return mls_context_cpy_low(newcontext, scontext);
default:
return -EINVAL;
}