[PATCH] SELinux: decouple fscontext/context mount options
Remove the conflict between fscontext and context mount options. If context= is specified without fscontext it will operate just as before, if both are specified we will use mount point labeling and all inodes will get the label specified by context=. The superblock will be labeled with the label of fscontext=, thus affecting operations which check the superblock security context, such as associate permissions. Signed-off-by: Eric Paris <eparis@parisplace.org> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
2ed6e34f88
commit
c312feb293
2 changed files with 56 additions and 16 deletions
|
@ -246,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb)
|
||||||
sbsec->sb = sb;
|
sbsec->sb = sb;
|
||||||
sbsec->sid = SECINITSID_UNLABELED;
|
sbsec->sid = SECINITSID_UNLABELED;
|
||||||
sbsec->def_sid = SECINITSID_FILE;
|
sbsec->def_sid = SECINITSID_FILE;
|
||||||
|
sbsec->mntpoint_sid = SECINITSID_UNLABELED;
|
||||||
sb->s_security = sbsec;
|
sb->s_security = sbsec;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -329,9 +330,26 @@ static match_table_t tokens = {
|
||||||
|
|
||||||
#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
|
#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"
|
||||||
|
|
||||||
|
static int may_context_mount_sb_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(tsec->sid, sid, SECCLASS_FILESYSTEM,
|
||||||
|
FILESYSTEM__RELABELTO, 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;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 sid;
|
u32 sid;
|
||||||
int alloc = 0, rc = 0, seen = 0;
|
int alloc = 0, rc = 0, seen = 0;
|
||||||
|
@ -374,7 +392,7 @@ static int try_context_mount(struct super_block *sb, void *data)
|
||||||
|
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case Opt_context:
|
case Opt_context:
|
||||||
if (seen) {
|
if (seen & (Opt_context|Opt_defcontext)) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
|
printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
@ -390,13 +408,13 @@ static int try_context_mount(struct super_block *sb, void *data)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Opt_fscontext:
|
case Opt_fscontext:
|
||||||
if (seen & (Opt_context|Opt_fscontext)) {
|
if (seen & Opt_fscontext) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
|
printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
context = match_strdup(&args[0]);
|
fscontext = match_strdup(&args[0]);
|
||||||
if (!context) {
|
if (!fscontext) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
@ -441,6 +459,28 @@ static int try_context_mount(struct super_block *sb, void *data)
|
||||||
if (!seen)
|
if (!seen)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* sets the context of the superblock for the fs being mounted. */
|
||||||
|
if (fscontext) {
|
||||||
|
rc = security_context_to_sid(fscontext, strlen(fscontext), &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;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
|
||||||
|
if (rc)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
sbsec->sid = sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch to using mount point labeling behavior.
|
||||||
|
* sets the label used on all file below the mountpoint, and will set
|
||||||
|
* the superblock context if not already set.
|
||||||
|
*/
|
||||||
if (context) {
|
if (context) {
|
||||||
rc = security_context_to_sid(context, strlen(context), &sid);
|
rc = security_context_to_sid(context, strlen(context), &sid);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -450,20 +490,15 @@ static int try_context_mount(struct super_block *sb, void *data)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
|
rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
|
||||||
FILESYSTEM__RELABELFROM, NULL);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
|
if (!fscontext)
|
||||||
FILESYSTEM__RELABELTO, NULL);
|
sbsec->sid = sid;
|
||||||
if (rc)
|
sbsec->mntpoint_sid = sid;
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
sbsec->sid = sid;
|
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
|
||||||
|
|
||||||
if (seen & Opt_context)
|
|
||||||
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defcontext) {
|
if (defcontext) {
|
||||||
|
@ -495,6 +530,7 @@ static int try_context_mount(struct super_block *sb, void *data)
|
||||||
if (alloc) {
|
if (alloc) {
|
||||||
kfree(context);
|
kfree(context);
|
||||||
kfree(defcontext);
|
kfree(defcontext);
|
||||||
|
kfree(fscontext);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -876,8 +912,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
||||||
goto out;
|
goto out;
|
||||||
isec->sid = sid;
|
isec->sid = sid;
|
||||||
break;
|
break;
|
||||||
|
case SECURITY_FS_USE_MNTPOINT:
|
||||||
|
isec->sid = sbsec->mntpoint_sid;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Default to the fs SID. */
|
/* Default to the fs superblock SID. */
|
||||||
isec->sid = sbsec->sid;
|
isec->sid = sbsec->sid;
|
||||||
|
|
||||||
if (sbsec->proc) {
|
if (sbsec->proc) {
|
||||||
|
|
|
@ -57,8 +57,9 @@ struct file_security_struct {
|
||||||
struct superblock_security_struct {
|
struct superblock_security_struct {
|
||||||
struct super_block *sb; /* back pointer to sb object */
|
struct super_block *sb; /* back pointer to sb object */
|
||||||
struct list_head list; /* list of superblock_security_struct */
|
struct list_head list; /* list of superblock_security_struct */
|
||||||
u32 sid; /* SID of file system */
|
u32 sid; /* SID of file system superblock */
|
||||||
u32 def_sid; /* default SID for labeling */
|
u32 def_sid; /* default SID for labeling */
|
||||||
|
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
|
||||||
unsigned int behavior; /* labeling behavior */
|
unsigned int behavior; /* labeling behavior */
|
||||||
unsigned char initialized; /* initialization flag */
|
unsigned char initialized; /* initialization flag */
|
||||||
unsigned char proc; /* proc fs */
|
unsigned char proc; /* proc fs */
|
||||||
|
|
Loading…
Reference in a new issue