]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - security/selinux/hooks.c
[PATCH] SELinux: add rootcontext= option to label root inode when mounting
[linux-2.6-omap-h63xx.git] / security / selinux / hooks.c
index 7e101dbea4cb28ffb381869904e0709debce56ee..2e8b4dfcbc743d4b2394085043f35793780ef1dc 100644 (file)
@@ -320,12 +320,14 @@ enum {
        Opt_context = 1,
        Opt_fscontext = 2,
        Opt_defcontext = 4,
+       Opt_rootcontext = 8,
 };
 
 static match_table_t tokens = {
        {Opt_context, "context=%s"},
        {Opt_fscontext, "fscontext=%s"},
        {Opt_defcontext, "defcontext=%s"},
+       {Opt_rootcontext, "rootcontext=%s"},
 };
 
 #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,
        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)
 {
        char *context = NULL, *defcontext = NULL;
-       char *fscontext = NULL;
+       char *fscontext = NULL, *rootcontext = NULL;
        const char *name;
        u32 sid;
        int alloc = 0, rc = 0, seen = 0;
@@ -423,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data)
                                seen |= Opt_fscontext;
                                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:
                                if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
                                        rc = -EINVAL;
@@ -501,6 +534,25 @@ static int try_context_mount(struct super_block *sb, void *data)
                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) {
                rc = security_context_to_sid(defcontext, strlen(defcontext), &sid);
                if (rc) {
@@ -513,13 +565,7 @@ static int try_context_mount(struct super_block *sb, void *data)
                if (sid == sbsec->def_sid)
                        goto out_free;
 
-               rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__RELABELFROM, NULL);
-               if (rc)
-                       goto out_free;
-
-               rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__ASSOCIATE, NULL);
+               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
                if (rc)
                        goto out_free;
 
@@ -531,6 +577,7 @@ out_free:
                kfree(context);
                kfree(defcontext);
                kfree(fscontext);
+               kfree(rootcontext);
        }
 out:
        return rc;
@@ -1882,7 +1929,8 @@ static inline int selinux_option(char *option, int len)
 {
        return (match_prefix("context=", sizeof("context=")-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)