diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7171a957b93..5c6f2cd2d09 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -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> @@ -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, @@ -4481,7 +4512,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; } |