Commit c312feb2 authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds

[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: 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 2ed6e34f
...@@ -246,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb) ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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,29 +459,46 @@ static int try_context_mount(struct super_block *sb, void *data) ...@@ -441,29 +459,46 @@ static int try_context_mount(struct super_block *sb, void *data)
if (!seen) if (!seen)
goto out; goto out;
if (context) { /* sets the context of the superblock for the fs being mounted. */
rc = security_context_to_sid(context, strlen(context), &sid); if (fscontext) {
rc = security_context_to_sid(fscontext, strlen(fscontext), &sid);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid" printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type %s) errno=%d\n",
context, sb->s_id, name, rc); fscontext, sb->s_id, name, rc);
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, sbsec->sid = sid;
FILESYSTEM__RELABELTO, NULL); }
/*
* 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) {
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;
}
rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
if (rc) if (rc)
goto out_free; goto out_free;
sbsec->sid = sid; if (!fscontext)
sbsec->sid = sid;
sbsec->mntpoint_sid = sid;
if (seen & Opt_context) sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
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) ...@@ -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 ...@@ -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 { ...@@ -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 */
......
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