Commit 0808925e authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds

[PATCH] SELinux: add rootcontext= option to label root inode when mounting

Introduce a new rootcontext= option to FS mounting.  This option will allow
you to explicitly label the root inode of an FS being mounted before that
FS or inode because visible to userspace.  This was found to be useful for
things like stateless linux, see
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=190001Signed-off-by: default avatarEric Paris <eparis@parisplace.org>
Acked-by: default avatarStephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c312feb2
...@@ -320,12 +320,14 @@ enum { ...@@ -320,12 +320,14 @@ enum {
Opt_context = 1, Opt_context = 1,
Opt_fscontext = 2, Opt_fscontext = 2,
Opt_defcontext = 4, Opt_defcontext = 4,
Opt_rootcontext = 8,
}; };
static match_table_t tokens = { static match_table_t tokens = {
{Opt_context, "context=%s"}, {Opt_context, "context=%s"},
{Opt_fscontext, "fscontext=%s"}, {Opt_fscontext, "fscontext=%s"},
{Opt_defcontext, "defcontext=%s"}, {Opt_defcontext, "defcontext=%s"},
{Opt_rootcontext, "rootcontext=%s"},
}; };
#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
...@@ -346,10 +348,25 @@ static int may_context_mount_sb_relabel(u32 sid, ...@@ -346,10 +348,25 @@ static int may_context_mount_sb_relabel(u32 sid,
return rc; return rc;
} }
static int may_context_mount_inode_relabel(u32 sid,
struct superblock_security_struct *sbsec,
struct task_security_struct *tsec)
{
int rc;
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
return rc;
}
static int try_context_mount(struct super_block *sb, void *data) static int try_context_mount(struct super_block *sb, void *data)
{ {
char *context = NULL, *defcontext = NULL; char *context = NULL, *defcontext = NULL;
char *fscontext = NULL; char *fscontext = NULL, *rootcontext = NULL;
const char *name; const char *name;
u32 sid; u32 sid;
int alloc = 0, rc = 0, seen = 0; int alloc = 0, rc = 0, seen = 0;
...@@ -423,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data) ...@@ -423,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data)
seen |= Opt_fscontext; seen |= Opt_fscontext;
break; break;
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;
case Opt_defcontext: case Opt_defcontext:
if (sbsec->behavior != SECURITY_FS_USE_XATTR) { if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
rc = -EINVAL; rc = -EINVAL;
...@@ -501,6 +534,25 @@ static int try_context_mount(struct super_block *sb, void *data) ...@@ -501,6 +534,25 @@ static int try_context_mount(struct super_block *sb, void *data)
sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 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 (rc)
goto out_free;
isec->sid = sid;
isec->initialized = 1;
}
if (defcontext) { if (defcontext) {
rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); rc = security_context_to_sid(defcontext, strlen(defcontext), &sid);
if (rc) { if (rc) {
...@@ -513,13 +565,7 @@ static int try_context_mount(struct super_block *sb, void *data) ...@@ -513,13 +565,7 @@ static int try_context_mount(struct super_block *sb, void *data)
if (sid == sbsec->def_sid) if (sid == sbsec->def_sid)
goto out_free; goto out_free;
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
FILESYSTEM__RELABELFROM, NULL);
if (rc)
goto out_free;
rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
if (rc) if (rc)
goto out_free; goto out_free;
...@@ -531,6 +577,7 @@ static int try_context_mount(struct super_block *sb, void *data) ...@@ -531,6 +577,7 @@ static int try_context_mount(struct super_block *sb, void *data)
kfree(context); kfree(context);
kfree(defcontext); kfree(defcontext);
kfree(fscontext); kfree(fscontext);
kfree(rootcontext);
} }
out: out:
return rc; return rc;
...@@ -1882,7 +1929,8 @@ static inline int selinux_option(char *option, int len) ...@@ -1882,7 +1929,8 @@ static inline int selinux_option(char *option, int len)
{ {
return (match_prefix("context=", sizeof("context=")-1, option, len) || return (match_prefix("context=", sizeof("context=")-1, option, len) ||
match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) ||
match_prefix("defcontext=", sizeof("defcontext=")-1, option, len)); match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) ||
match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len));
} }
static inline void take_option(char **to, char *from, int *first, int len) static inline void take_option(char **to, char *from, int *first, int len)
......
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