Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[pandora-kernel.git] / security / selinux / hooks.c
index 7171a95..feb2f42 100644 (file)
@@ -751,7 +751,37 @@ out_double_mount:
        goto out;
 }
 
-static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
+static int selinux_cmp_sb_context(const struct super_block *oldsb,
+                                   const struct super_block *newsb)
+{
+       struct superblock_security_struct *old = oldsb->s_security;
+       struct superblock_security_struct *new = newsb->s_security;
+       char oldflags = old->flags & SE_MNTMASK;
+       char newflags = new->flags & SE_MNTMASK;
+
+       if (oldflags != newflags)
+               goto mismatch;
+       if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
+               goto mismatch;
+       if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
+               goto mismatch;
+       if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
+               goto mismatch;
+       if (oldflags & ROOTCONTEXT_MNT) {
+               struct inode_security_struct *oldroot = oldsb->s_root->d_inode->i_security;
+               struct inode_security_struct *newroot = newsb->s_root->d_inode->i_security;
+               if (oldroot->sid != newroot->sid)
+                       goto mismatch;
+       }
+       return 0;
+mismatch:
+       printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, "
+                           "different security settings for (dev %s, "
+                           "type %s)\n", newsb->s_id, newsb->s_type->name);
+       return -EBUSY;
+}
+
+static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
                                        struct super_block *newsb)
 {
        const struct superblock_security_struct *oldsbsec = oldsb->s_security;
@@ -766,14 +796,14 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
         * mount options.  thus we can safely deal with this superblock later
         */
        if (!ss_initialized)
-               return;
+               return 0;
 
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
 
-       /* if fs is reusing a sb, just let its options stand... */
+       /* if fs is reusing a sb, make sure that the contexts match */
        if (newsbsec->flags & SE_SBINITIALIZED)
-               return;
+               return selinux_cmp_sb_context(oldsb, newsb);
 
        mutex_lock(&newsbsec->lock);
 
@@ -806,6 +836,7 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 
        sb_finish_set_opts(newsb);
        mutex_unlock(&newsbsec->lock);
+       return 0;
 }
 
 static int selinux_parse_opts_str(char *options,