]> Pileus Git - ~andy/linux/blobdiff - security/selinux/hooks.c
SELinux: remove crazy contortions around proc
[~andy/linux] / security / selinux / hooks.c
index 7171a957b9335694c1bbd1c5c9a41e2ec13bbda9..42b538ceb8b421a7976e5a324e782801e333f695 100644 (file)
@@ -61,7 +61,7 @@
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>   /* for network interface checks */
-#include <linux/netlink.h>
+#include <net/netlink.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/dccp.h>
@@ -406,6 +406,13 @@ static int sb_finish_set_opts(struct super_block *sb)
        if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
                sbsec->flags |= SE_SBLABELSUPP;
 
+       /*
+        * Special handling for rootfs. Is genfs but supports
+        * setting SELinux context on in-core inodes.
+        */
+       if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
+               sbsec->flags |= SE_SBLABELSUPP;
+
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
 
@@ -671,7 +678,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                sbsec->flags |= SE_SBPROC;
 
        /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
                       __func__, sb->s_type->name, rc);
@@ -751,7 +758,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 +803,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 +843,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,
@@ -3691,8 +3729,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
        u32 nlbl_sid;
        u32 nlbl_type;
 
-       selinux_skb_xfrm_sid(skb, &xfrm_sid);
-       selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
+       err = selinux_skb_xfrm_sid(skb, &xfrm_sid);
+       if (unlikely(err))
+               return -EACCES;
+       err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
+       if (unlikely(err))
+               return -EACCES;
 
        err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
        if (unlikely(err)) {
@@ -4481,7 +4523,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        struct nlmsghdr *nlh;
        struct sk_security_struct *sksec = sk->sk_security;
 
-       if (skb->len < NLMSG_SPACE(0)) {
+       if (skb->len < NLMSG_HDRLEN) {
                err = -EINVAL;
                goto out;
        }
@@ -5677,7 +5719,8 @@ static struct security_operations selinux_ops = {
        .xfrm_policy_clone_security =   selinux_xfrm_policy_clone,
        .xfrm_policy_free_security =    selinux_xfrm_policy_free,
        .xfrm_policy_delete_security =  selinux_xfrm_policy_delete,
-       .xfrm_state_alloc_security =    selinux_xfrm_state_alloc,
+       .xfrm_state_alloc =             selinux_xfrm_state_alloc,
+       .xfrm_state_alloc_acquire =     selinux_xfrm_state_alloc_acquire,
        .xfrm_state_free_security =     selinux_xfrm_state_free,
        .xfrm_state_delete_security =   selinux_xfrm_state_delete,
        .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,