]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - security/selinux/hooks.c
selinux: never allow relabeling on context mounts
[mirror_ubuntu-bionic-kernel.git] / security / selinux / hooks.c
index 8644d864e3c196ca3dc8a10cb84c2daa97e3a596..beb0921a2a7d87a129ca0fb46649e6f8b993a9c2 100644 (file)
@@ -129,9 +129,6 @@ __setup("selinux=", selinux_enabled_setup);
 int selinux_enabled = 1;
 #endif
 
-static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
-
 /**
  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
  *
@@ -192,12 +189,9 @@ static void cred_init_security(void)
        struct cred *cred = (struct cred *) current->real_cred;
        struct task_security_struct *tsec;
 
-       tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
-       if (!tsec)
-               panic("SELinux:  Failed to initialize initial task.\n");
-
+       lsm_early_cred(cred);
+       tsec = selinux_cred(cred);
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
-       cred->security = tsec;
 }
 
 /*
@@ -207,7 +201,7 @@ static inline u32 cred_sid(const struct cred *cred)
 {
        const struct task_security_struct *tsec;
 
-       tsec = cred->security;
+       tsec = selinux_cred(cred);
        return tsec->sid;
 }
 
@@ -228,13 +222,9 @@ static inline u32 task_sid(const struct task_struct *task)
 
 static int inode_alloc_security(struct inode *inode)
 {
-       struct inode_security_struct *isec;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = current_sid();
 
-       isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
-       if (!isec)
-               return -ENOMEM;
-
        spin_lock_init(&isec->lock);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@ -242,7 +232,6 @@ static int inode_alloc_security(struct inode *inode)
        isec->sclass = SECCLASS_FILE;
        isec->task_sid = sid;
        isec->initialized = LABEL_INVALID;
-       inode->i_security = isec;
 
        return 0;
 }
@@ -260,7 +249,7 @@ static int __inode_security_revalidate(struct inode *inode,
                                       struct dentry *opt_dentry,
                                       bool may_sleep)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
 
        might_sleep_if(may_sleep);
 
@@ -280,7 +269,7 @@ static int __inode_security_revalidate(struct inode *inode,
 
 static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
 {
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
@@ -290,7 +279,7 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
        error = __inode_security_revalidate(inode, NULL, !rcu);
        if (error)
                return ERR_PTR(error);
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 /*
@@ -299,14 +288,14 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
 static struct inode_security_struct *inode_security(struct inode *inode)
 {
        __inode_security_revalidate(inode, NULL, true);
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
 {
        struct inode *inode = d_backing_inode(dentry);
 
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 /*
@@ -317,21 +306,14 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
        struct inode *inode = d_backing_inode(dentry);
 
        __inode_security_revalidate(inode, dentry, true);
-       return inode->i_security;
-}
-
-static void inode_free_rcu(struct rcu_head *head)
-{
-       struct inode_security_struct *isec;
-
-       isec = container_of(head, struct inode_security_struct, rcu);
-       kmem_cache_free(sel_inode_cache, isec);
+       return selinux_inode(inode);
 }
 
 static void inode_free_security(struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
-       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
+       struct superblock_security_struct *sbsec =
+                                       selinux_superblock(inode->i_sb);
 
        /*
         * As not all inode security structures are in a list, we check for
@@ -348,49 +330,22 @@ static void inode_free_security(struct inode *inode)
                list_del_init(&isec->list);
                spin_unlock(&sbsec->isec_lock);
        }
-
-       /*
-        * The inode may still be referenced in a path walk and
-        * a call to selinux_inode_permission() can be made
-        * after inode_free_security() is called. Ideally, the VFS
-        * wouldn't do this, but fixing that is a much harder
-        * job. For now, simply free the i_security via RCU, and
-        * leave the current inode->i_security pointer intact.
-        * The inode will be freed after the RCU grace period too.
-        */
-       call_rcu(&isec->rcu, inode_free_rcu);
 }
 
 static int file_alloc_security(struct file *file)
 {
-       struct file_security_struct *fsec;
+       struct file_security_struct *fsec = selinux_file(file);
        u32 sid = current_sid();
 
-       fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
-       if (!fsec)
-               return -ENOMEM;
-
        fsec->sid = sid;
        fsec->fown_sid = sid;
-       file->f_security = fsec;
 
        return 0;
 }
 
-static void file_free_security(struct file *file)
-{
-       struct file_security_struct *fsec = file->f_security;
-       file->f_security = NULL;
-       kmem_cache_free(file_security_cache, fsec);
-}
-
 static int superblock_alloc_security(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec;
-
-       sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
-       if (!sbsec)
-               return -ENOMEM;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
        mutex_init(&sbsec->lock);
        INIT_LIST_HEAD(&sbsec->isec_head);
@@ -399,18 +354,10 @@ static int superblock_alloc_security(struct super_block *sb)
        sbsec->sid = SECINITSID_UNLABELED;
        sbsec->def_sid = SECINITSID_FILE;
        sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-       sb->s_security = sbsec;
 
        return 0;
 }
 
-static void superblock_free_security(struct super_block *sb)
-{
-       struct superblock_security_struct *sbsec = sb->s_security;
-       sb->s_security = NULL;
-       kfree(sbsec);
-}
-
 static inline int inode_doinit(struct inode *inode)
 {
        return inode_doinit_with_dentry(inode, NULL);
@@ -443,7 +390,7 @@ static int may_context_mount_sb_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
 {
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
 
        rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -460,7 +407,7 @@ static int may_context_mount_inode_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
 {
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
        rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
@@ -472,16 +419,10 @@ static int may_context_mount_inode_relabel(u32 sid,
        return rc;
 }
 
-static int selinux_is_sblabel_mnt(struct super_block *sb)
+static int selinux_is_genfs_special_handling(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
-
-       return sbsec->behavior == SECURITY_FS_USE_XATTR ||
-               sbsec->behavior == SECURITY_FS_USE_TRANS ||
-               sbsec->behavior == SECURITY_FS_USE_TASK ||
-               sbsec->behavior == SECURITY_FS_USE_NATIVE ||
-               /* Special handling. Genfs but also in-core setxattr handler */
-               !strcmp(sb->s_type->name, "sysfs") ||
+       /* Special handling. Genfs but also in-core setxattr handler */
+       return  !strcmp(sb->s_type->name, "sysfs") ||
                !strcmp(sb->s_type->name, "pstore") ||
                !strcmp(sb->s_type->name, "debugfs") ||
                !strcmp(sb->s_type->name, "tracefs") ||
@@ -491,9 +432,37 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
                  !strcmp(sb->s_type->name, "cgroup2")));
 }
 
-static int sb_finish_set_opts(struct super_block *sb)
+static int selinux_is_sblabel_mnt(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
+
+       /*
+        * IMPORTANT: Double-check logic in this function when adding a new
+        * SECURITY_FS_USE_* definition!
+        */
+       BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
+
+       switch (sbsec->behavior) {
+       case SECURITY_FS_USE_XATTR:
+       case SECURITY_FS_USE_TRANS:
+       case SECURITY_FS_USE_TASK:
+       case SECURITY_FS_USE_NATIVE:
+               return 1;
+
+       case SECURITY_FS_USE_GENFS:
+               return selinux_is_genfs_special_handling(sb);
+
+       /* Never allow relabeling on context mounts */
+       case SECURITY_FS_USE_MNTPOINT:
+       case SECURITY_FS_USE_NONE:
+       default:
+               return 0;
+       }
+}
+
+static int sb_finish_set_opts(struct super_block *sb)
+{
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
        struct dentry *root = sb->s_root;
        struct inode *root_inode = d_backing_inode(root);
        int rc = 0;
@@ -576,7 +545,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                                struct security_mnt_opts *opts)
 {
        int rc = 0, i;
-       struct superblock_security_struct *sbsec = sb->s_security;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
        char *context = NULL;
        u32 len;
        char tmp;
@@ -639,7 +608,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
        }
        if (sbsec->flags & ROOTCONTEXT_MNT) {
                struct dentry *root = sbsec->sb->s_root;
-               struct inode_security_struct *isec = backing_inode_security(root);
+               struct inode_security_struct *isec =
+                                               backing_inode_security(root);
 
                rc = security_sid_to_context(isec->sid, &context, &len);
                if (rc)
@@ -692,7 +662,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 {
        const struct cred *cred = current_cred();
        int rc = 0, i;
-       struct superblock_security_struct *sbsec = sb->s_security;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
        const char *name = sb->s_type->name;
        struct dentry *root = sbsec->sb->s_root;
        struct inode_security_struct *root_isec;
@@ -943,8 +913,8 @@ out_double_mount:
 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;
+       struct superblock_security_struct *old = selinux_superblock(oldsb);
+       struct superblock_security_struct *new = selinux_superblock(newsb);
        char oldflags = old->flags & SE_MNTMASK;
        char newflags = new->flags & SE_MNTMASK;
 
@@ -976,8 +946,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
                                        unsigned long *set_kern_flags)
 {
        int rc = 0;
-       const struct superblock_security_struct *oldsbsec = oldsb->s_security;
-       struct superblock_security_struct *newsbsec = newsb->s_security;
+       const struct superblock_security_struct *oldsbsec =
+                                               selinux_superblock(oldsb);
+       struct superblock_security_struct *newsbsec = selinux_superblock(newsb);
 
        int set_fscontext =     (oldsbsec->flags & FSCONTEXT_MNT);
        int set_context =       (oldsbsec->flags & CONTEXT_MNT);
@@ -1001,8 +972,11 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
 
        /* if fs is reusing a sb, make sure that the contexts match */
-       if (newsbsec->flags & SE_SBINITIALIZED)
+       if (newsbsec->flags & SE_SBINITIALIZED) {
+               if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
+                       *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
                return selinux_cmp_sb_context(oldsb, newsb);
+       }
 
        mutex_lock(&newsbsec->lock);
 
@@ -1030,14 +1004,17 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
                if (!set_fscontext)
                        newsbsec->sid = sid;
                if (!set_rootcontext) {
-                       struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
+                       struct inode_security_struct *newisec =
+                                       backing_inode_security(newsb->s_root);
                        newisec->sid = sid;
                }
                newsbsec->mntpoint_sid = sid;
        }
        if (set_rootcontext) {
-               const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
-               struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
+               const struct inode_security_struct *oldisec =
+                                       backing_inode_security(oldsb->s_root);
+               struct inode_security_struct *newisec =
+                                       backing_inode_security(newsb->s_root);
 
                newisec->sid = oldisec->sid;
        }
@@ -1472,6 +1449,11 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
                        }
                }
                rc = security_genfs_sid(sb->s_type->name, path, tclass, sid);
+               if (rc == -ENOENT) {
+                       /* No match in policy, mark as unlabeled. */
+                       *sid = SECINITSID_UNLABELED;
+                       rc = 0;
+               }
        }
        free_page((unsigned long)buffer);
        return rc;
@@ -1481,7 +1463,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
 {
        struct superblock_security_struct *sbsec = NULL;
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 task_sid, sid = 0;
        u16 sclass;
        struct dentry *dentry;
@@ -1500,7 +1482,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
        if (isec->sclass == SECCLASS_FILE)
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
 
-       sbsec = inode->i_sb->s_security;
+       sbsec = selinux_superblock(inode->i_sb);
        if (!(sbsec->flags & SE_SBINITIALIZED)) {
                /* Defer initialization until selinux_complete_init,
                   after the initial policy is loaded and the security
@@ -1532,8 +1514,15 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        /* Called from d_instantiate or d_splice_alias. */
                        dentry = dget(opt_dentry);
                } else {
-                       /* Called from selinux_complete_init, try to find a dentry. */
+                       /*
+                        * Called from selinux_complete_init, try to find a dentry.
+                        * Some filesystems really want a connected one, so try
+                        * that first.  We could split SECURITY_FS_USE_XATTR in
+                        * two, depending upon that...
+                        */
                        dentry = d_find_alias(inode);
+                       if (!dentry)
+                               dentry = d_find_any_alias(inode);
                }
                if (!dentry) {
                        /*
@@ -1636,14 +1625,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
                        /* We must have a dentry to determine the label on
                         * procfs inodes */
-                       if (opt_dentry)
+                       if (opt_dentry) {
                                /* Called from d_instantiate or
                                 * d_splice_alias. */
                                dentry = dget(opt_dentry);
-                       else
+                       } else {
                                /* Called from selinux_complete_init, try to
-                                * find a dentry. */
+                                * find a dentry.  Some filesystems really want
+                                * a connected one, so try that first.
+                                */
                                dentry = d_find_alias(inode);
+                               if (!dentry)
+                                       dentry = d_find_any_alias(inode);
+                       }
                        /*
                         * This can be hit on boot when a file is accessed
                         * before the policy is loaded.  When we load policy we
@@ -1766,7 +1760,7 @@ static int inode_has_perm(const struct cred *cred,
                return 0;
 
        sid = cred_sid(cred);
-       isec = inode->i_security;
+       isec = selinux_inode(inode);
 
        return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
@@ -1831,7 +1825,7 @@ static int file_has_perm(const struct cred *cred,
                         struct file *file,
                         u32 av)
 {
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct common_audit_data ad;
        u32 sid = cred_sid(cred);
@@ -1873,7 +1867,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
                                 const struct qstr *name, u16 tclass,
                                 u32 *_new_isid)
 {
-       const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
+       const struct superblock_security_struct *sbsec =
+                                               selinux_superblock(dir->i_sb);
 
        if ((sbsec->flags & SE_SBINITIALIZED) &&
            (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
@@ -1895,7 +1890,7 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
@@ -1903,7 +1898,7 @@ static int may_create(struct inode *dir,
        int rc;
 
        dsec = inode_security(dir);
-       sbsec = dir->i_sb->s_security;
+       sbsec = selinux_superblock(dir->i_sb);
 
        sid = tsec->sid;
 
@@ -1916,7 +1911,7 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       rc = selinux_determine_inode_label(current_security(), dir,
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir,
                                           &dentry->d_name, tclass, &newsid);
        if (rc)
                return rc;
@@ -2042,7 +2037,7 @@ static int superblock_has_perm(const struct cred *cred,
        struct superblock_security_struct *sbsec;
        u32 sid = cred_sid(cred);
 
-       sbsec = sb->s_security;
+       sbsec = selinux_superblock(sb);
        return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
 }
 
@@ -2157,7 +2152,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
                                        struct file *file)
 {
        u32 sid = task_sid(to);
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct dentry *dentry = file->f_path.dentry;
        struct inode_security_struct *isec;
        struct common_audit_data ad;
@@ -2335,7 +2330,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
                            const struct task_security_struct *new_tsec)
 {
        int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
-       int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
+       int nosuid = path_nosuid(&bprm->file->f_path);
        int rc;
        u32 av;
 
@@ -2396,8 +2391,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->called_set_creds)
                return 0;
 
-       old_tsec = current_security();
-       new_tsec = bprm->cred->security;
+       old_tsec = selinux_cred(current_cred());
+       new_tsec = selinux_cred(bprm->cred);
        isec = inode_security(inode);
 
        /* Default to the current task SID. */
@@ -2555,7 +2550,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
        struct rlimit *rlim, *initrlim;
        int rc, i;
 
-       new_tsec = bprm->cred->security;
+       new_tsec = selinux_cred(bprm->cred);
        if (new_tsec->sid == new_tsec->osid)
                return;
 
@@ -2597,7 +2592,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
  */
 static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct itimerval itimer;
        u32 osid, sid;
        int rc, i;
@@ -2647,11 +2642,6 @@ static int selinux_sb_alloc_security(struct super_block *sb)
        return superblock_alloc_security(sb);
 }
 
-static void selinux_sb_free_security(struct super_block *sb)
-{
-       superblock_free_security(sb);
-}
-
 static inline int match_prefix(char *prefix, int plen, char *option, int olen)
 {
        if (plen > olen)
@@ -2748,7 +2738,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
        int rc, i, *flags;
        struct security_mnt_opts opts;
        char *secdata, **mount_options;
-       struct superblock_security_struct *sbsec = sb->s_security;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
        if (!(sbsec->flags & SE_SBINITIALIZED))
                return 0;
@@ -2837,7 +2827,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
                return rc;
 
        /* Allow all mounts performed by the kernel */
-       if (flags & MS_KERNMOUNT)
+       if (flags & (MS_KERNMOUNT | MS_SUBMOUNT))
                return 0;
 
        ad.type = LSM_AUDIT_DATA_DENTRY;
@@ -2897,7 +2887,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
        u32 newsid;
        int rc;
 
-       rc = selinux_determine_inode_label(current_security(),
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
@@ -2916,14 +2906,14 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
        int rc;
        struct task_security_struct *tsec;
 
-       rc = selinux_determine_inode_label(old->security,
+       rc = selinux_determine_inode_label(selinux_cred(old),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
        if (rc)
                return rc;
 
-       tsec = new->security;
+       tsec = selinux_cred(new);
        tsec->create_sid = newsid;
        return 0;
 }
@@ -2933,17 +2923,17 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       const char **name,
                                       void **value, size_t *len)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct superblock_security_struct *sbsec;
        u32 newsid, clen;
        int rc;
        char *context;
 
-       sbsec = dir->i_sb->s_security;
+       sbsec = selinux_superblock(dir->i_sb);
 
        newsid = tsec->create_sid;
 
-       rc = selinux_determine_inode_label(current_security(),
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                dir, qstr,
                inode_mode_to_security_class(inode->i_mode),
                &newsid);
@@ -2952,7 +2942,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        /* Possibly defer initialization to selinux_complete_init. */
        if (sbsec->flags & SE_SBINITIALIZED) {
-               struct inode_security_struct *isec = inode->i_security;
+               struct inode_security_struct *isec = selinux_inode(inode);
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
                isec->sid = newsid;
                isec->initialized = LABEL_INITIALIZED;
@@ -3050,7 +3040,7 @@ static noinline int audit_inode_permission(struct inode *inode,
                                           unsigned flags)
 {
        struct common_audit_data ad;
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        int rc;
 
        ad.type = LSM_AUDIT_DATA_INODE;
@@ -3172,7 +3162,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
        }
 
-       sbsec = inode->i_sb->s_security;
+       sbsec = selinux_superblock(inode->i_sb);
        if (!(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
@@ -3344,12 +3334,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                                     const void *value, size_t size, int flags)
 {
        struct inode_security_struct *isec = inode_security_novalidate(inode);
+       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
        u32 newsid;
        int rc;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
+       if (!(sbsec->flags & SBLABEL_MNT))
+               return -EOPNOTSUPP;
+
        if (!value || !size)
                return -EACCES;
 
@@ -3391,7 +3385,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
                        return -ENOMEM;
        }
 
-       tsec = new_creds->security;
+       tsec = selinux_cred(new_creds);
        /* Get label from overlay inode and set it in create_sid */
        selinux_inode_getsecid(d_inode(src), &sid);
        tsec->create_sid = sid;
@@ -3432,7 +3426,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
 static int selinux_file_permission(struct file *file, int mask)
 {
        struct inode *inode = file_inode(file);
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode_security_struct *isec;
        u32 sid = current_sid();
 
@@ -3454,11 +3448,6 @@ static int selinux_file_alloc_security(struct file *file)
        return file_alloc_security(file);
 }
 
-static void selinux_file_free_security(struct file *file)
-{
-       file_free_security(file);
-}
-
 /*
  * Check whether a task has the ioctl permission and cmd
  * operation to an inode.
@@ -3467,7 +3456,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
                u32 requested, u16 cmd)
 {
        struct common_audit_data ad;
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct inode_security_struct *isec;
        struct lsm_ioctlop_audit ioctl;
@@ -3713,7 +3702,7 @@ static void selinux_file_set_fowner(struct file *file)
 {
        struct file_security_struct *fsec;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        fsec->fown_sid = current_sid();
 }
 
@@ -3728,7 +3717,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
        /* struct fown_struct is never outside the context of a struct file */
        file = container_of(fown, struct file, f_owner);
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
 
        if (!signum)
                perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
@@ -3751,7 +3740,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
        struct file_security_struct *fsec;
        struct inode_security_struct *isec;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        isec = inode_security(file_inode(file));
        /*
         * Save inode label and policy sequence number
@@ -3783,53 +3772,17 @@ static int selinux_task_alloc(struct task_struct *task,
        return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
 }
 
-/*
- * allocate the SELinux part of blank credentials
- */
-static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
-{
-       struct task_security_struct *tsec;
-
-       tsec = kzalloc(sizeof(struct task_security_struct), gfp);
-       if (!tsec)
-               return -ENOMEM;
-
-       cred->security = tsec;
-       return 0;
-}
-
-/*
- * detach and free the LSM part of a set of credentials
- */
-static void selinux_cred_free(struct cred *cred)
-{
-       struct task_security_struct *tsec = cred->security;
-
-       /*
-        * cred->security == NULL if security_cred_alloc_blank() or
-        * security_prepare_creds() returned an error.
-        */
-       BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
-       cred->security = (void *) 0x7UL;
-       kfree(tsec);
-}
-
 /*
  * prepare a new set of credentials for modification
  */
 static int selinux_cred_prepare(struct cred *new, const struct cred *old,
                                gfp_t gfp)
 {
-       const struct task_security_struct *old_tsec;
-       struct task_security_struct *tsec;
+       const struct task_security_struct *old_tsec = selinux_cred(old);
+       struct task_security_struct *tsec = selinux_cred(new);
 
-       old_tsec = old->security;
-
-       tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
-       if (!tsec)
-               return -ENOMEM;
+       *tsec = *old_tsec;
 
-       new->security = tsec;
        return 0;
 }
 
@@ -3838,8 +3791,8 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void selinux_cred_transfer(struct cred *new, const struct cred *old)
 {
-       const struct task_security_struct *old_tsec = old->security;
-       struct task_security_struct *tsec = new->security;
+       const struct task_security_struct *old_tsec = selinux_cred(old);
+       struct task_security_struct *tsec = selinux_cred(new);
 
        *tsec = *old_tsec;
 }
@@ -3850,7 +3803,7 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old)
  */
 static int selinux_kernel_act_as(struct cred *new, u32 secid)
 {
-       struct task_security_struct *tsec = new->security;
+       struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
 
@@ -3874,7 +3827,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
 static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 {
        struct inode_security_struct *isec = inode_security(inode);
-       struct task_security_struct *tsec = new->security;
+       struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
 
@@ -3917,7 +3870,7 @@ static int selinux_kernel_module_from_file(struct file *file)
        ad.type = LSM_AUDIT_DATA_FILE;
        ad.u.file = file;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        if (sid != fsec->sid) {
                rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
                if (rc)
@@ -4052,7 +4005,7 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
 static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = task_sid(p);
 
        spin_lock(&isec->lock);
@@ -4338,7 +4291,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
 
 static int sock_has_perm(struct sock *sk, u32 perms)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
 
@@ -4356,7 +4309,7 @@ static int sock_has_perm(struct sock *sk, u32 perms)
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        u32 newsid;
        u16 secclass;
        int rc;
@@ -4375,7 +4328,7 @@ static int selinux_socket_create(int family, int type,
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
        struct sk_security_struct *sksec;
        u16 sclass = socket_type_to_security_class(family, type, protocol);
@@ -4393,7 +4346,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
        isec->initialized = LABEL_INITIALIZED;
 
        if (sock->sk) {
-               sksec = sock->sk->sk_security;
+               sksec = selinux_sock(sock->sk);
                sksec->sclass = sclass;
                sksec->sid = sid;
                err = selinux_netlbl_socket_post_create(sock->sk, family);
@@ -4424,7 +4377,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
        family = sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
-               struct sk_security_struct *sksec = sk->sk_security;
+               struct sk_security_struct *sksec = selinux_sock(sk);
                struct common_audit_data ad;
                struct lsm_network_audit net = {0,};
                struct sockaddr_in *addr4 = NULL;
@@ -4517,7 +4470,7 @@ out:
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        int err;
 
        err = sock_has_perm(sk, SOCKET__CONNECT);
@@ -4649,9 +4602,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
                                              struct sock *other,
                                              struct sock *newsk)
 {
-       struct sk_security_struct *sksec_sock = sock->sk_security;
-       struct sk_security_struct *sksec_other = other->sk_security;
-       struct sk_security_struct *sksec_new = newsk->sk_security;
+       struct sk_security_struct *sksec_sock = selinux_sock(sock);
+       struct sk_security_struct *sksec_other = selinux_sock(other);
+       struct sk_security_struct *sksec_new = selinux_sock(newsk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
        int err;
@@ -4682,8 +4635,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
 static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
 {
-       struct sk_security_struct *ssec = sock->sk->sk_security;
-       struct sk_security_struct *osec = other->sk->sk_security;
+       struct sk_security_struct *ssec = selinux_sock(sock->sk);
+       struct sk_security_struct *osec = selinux_sock(other->sk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
 
@@ -4722,7 +4675,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                                       u16 family)
 {
        int err = 0;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
@@ -4754,7 +4707,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
@@ -4820,13 +4773,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        return err;
 }
 
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-                                           int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock,
+                                           __user char *optval,
+                                           __user int *optlen,
+                                           unsigned int len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
-       struct sk_security_struct *sksec = sock->sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sock->sk);
        u32 peer_sid = SECSID_NULL;
 
        if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
@@ -4884,34 +4839,27 @@ out:
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-       struct sk_security_struct *sksec;
-
-       sksec = kzalloc(sizeof(*sksec), priority);
-       if (!sksec)
-               return -ENOMEM;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        sksec->peer_sid = SECINITSID_UNLABELED;
        sksec->sid = SECINITSID_UNLABELED;
        sksec->sclass = SECCLASS_SOCKET;
        selinux_netlbl_sk_security_reset(sksec);
-       sk->sk_security = sksec;
 
        return 0;
 }
 
 static void selinux_sk_free_security(struct sock *sk)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
-       sk->sk_security = NULL;
        selinux_netlbl_sk_security_free(sksec);
-       kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
-       struct sk_security_struct *newsksec = newsk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
+       struct sk_security_struct *newsksec = selinux_sock(newsk);
 
        newsksec->sid = sksec->sid;
        newsksec->peer_sid = sksec->peer_sid;
@@ -4925,7 +4873,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
        if (!sk)
                *secid = SECINITSID_ANY_SOCKET;
        else {
-               struct sk_security_struct *sksec = sk->sk_security;
+               struct sk_security_struct *sksec = selinux_sock(sk);
 
                *secid = sksec->sid;
        }
@@ -4935,7 +4883,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct inode_security_struct *isec =
                inode_security_novalidate(SOCK_INODE(parent));
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
            sk->sk_family == PF_UNIX)
@@ -4946,7 +4894,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
                                     struct request_sock *req)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        int err;
        u16 family = req->rsk_ops->family;
        u32 connsid;
@@ -4967,7 +4915,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 static void selinux_inet_csk_clone(struct sock *newsk,
                                   const struct request_sock *req)
 {
-       struct sk_security_struct *newsksec = newsk->sk_security;
+       struct sk_security_struct *newsksec = selinux_sock(newsk);
 
        newsksec->sid = req->secid;
        newsksec->peer_sid = req->peer_secid;
@@ -4984,7 +4932,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
 static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
        u16 family = sk->sk_family;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        /* handle mapped IPv4 packets arriving via IPv6 sockets */
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -4998,7 +4946,7 @@ static int selinux_secmark_relabel_packet(u32 sid)
        const struct task_security_struct *__tsec;
        u32 tsid;
 
-       __tsec = current_security();
+       __tsec = selinux_cred(current_cred());
        tsid = __tsec->sid;
 
        return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
@@ -5064,7 +5012,7 @@ static int selinux_tun_dev_attach_queue(void *security)
 static int selinux_tun_dev_attach(struct sock *sk, void *security)
 {
        struct tun_security_struct *tunsec = security;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        /* we don't currently perform any NetLabel based labeling here and it
         * isn't clear that we would want to do so anyway; while we could apply
@@ -5103,7 +5051,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        int err = 0;
        u32 perm;
        struct nlmsghdr *nlh;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        if (skb->len < NLMSG_HDRLEN) {
                err = -EINVAL;
@@ -5242,7 +5190,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
                        return NF_ACCEPT;
 
                /* standard practice, label using the parent socket */
-               sksec = sk->sk_security;
+               sksec = selinux_sock(sk);
                sid = sksec->sid;
        } else
                sid = SECINITSID_KERNEL;
@@ -5281,7 +5229,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 
        if (sk == NULL)
                return NF_ACCEPT;
-       sksec = sk->sk_security;
+       sksec = selinux_sock(sk);
 
        ad.type = LSM_AUDIT_DATA_NET;
        ad.u.net = &net;
@@ -5372,7 +5320,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
                u32 skb_sid;
                struct sk_security_struct *sksec;
 
-               sksec = sk->sk_security;
+               sksec = selinux_sock(sk);
                if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
                        return NF_DROP;
                /* At this point, if the returned skb peerlbl is SECSID_NULL
@@ -5401,7 +5349,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
        } else {
                /* Locally generated packet, fetch the security label from the
                 * associated socket. */
-               struct sk_security_struct *sksec = sk->sk_security;
+               struct sk_security_struct *sksec = selinux_sock(sk);
                peer_sid = sksec->sid;
                secmark_perm = PACKET__SEND;
        }
@@ -5461,51 +5409,22 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return selinux_nlmsg_perm(sk, skb);
 }
 
-static int ipc_alloc_security(struct kern_ipc_perm *perm,
-                             u16 sclass)
+static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
 {
-       struct ipc_security_struct *isec;
-
-       isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
-       if (!isec)
-               return -ENOMEM;
-
        isec->sclass = sclass;
        isec->sid = current_sid();
-       perm->security = isec;
-
-       return 0;
-}
-
-static void ipc_free_security(struct kern_ipc_perm *perm)
-{
-       struct ipc_security_struct *isec = perm->security;
-       perm->security = NULL;
-       kfree(isec);
 }
 
 static int msg_msg_alloc_security(struct msg_msg *msg)
 {
        struct msg_security_struct *msec;
 
-       msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
-       if (!msec)
-               return -ENOMEM;
-
+       msec = selinux_msg_msg(msg);
        msec->sid = SECINITSID_UNLABELED;
-       msg->security = msec;
 
        return 0;
 }
 
-static void msg_msg_free_security(struct msg_msg *msg)
-{
-       struct msg_security_struct *msec = msg->security;
-
-       msg->security = NULL;
-       kfree(msec);
-}
-
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
@@ -5513,7 +5432,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = ipc_perms->security;
+       isec = selinux_ipc(ipc_perms);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = ipc_perms->key;
@@ -5526,11 +5445,6 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
        return msg_msg_alloc_security(msg);
 }
 
-static void selinux_msg_msg_free_security(struct msg_msg *msg)
-{
-       msg_msg_free_security(msg);
-}
-
 /* message queue security operations */
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
@@ -5539,27 +5453,15 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(&msq->q_perm, SECCLASS_MSGQ);
-       if (rc)
-               return rc;
-
-       isec = msq->q_perm.security;
+       isec = selinux_ipc(&msq->q_perm);
+       ipc_init_security(isec, SECCLASS_MSGQ);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(&msq->q_perm);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_msg_queue_free_security(struct msg_queue *msq)
-{
-       ipc_free_security(&msq->q_perm);
+       return rc;
 }
 
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
@@ -5568,7 +5470,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = msq->q_perm.security;
+       isec = selinux_ipc(&msq->q_perm);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->q_perm.key;
@@ -5614,8 +5516,8 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
        u32 sid = current_sid();
        int rc;
 
-       isec = msq->q_perm.security;
-       msec = msg->security;
+       isec = selinux_ipc(&msq->q_perm);
+       msec = selinux_msg_msg(msg);
 
        /*
         * First time through, need to assign label to the message
@@ -5659,8 +5561,8 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
        u32 sid = task_sid(target);
        int rc;
 
-       isec = msq->q_perm.security;
-       msec = msg->security;
+       isec = selinux_ipc(&msq->q_perm);
+       msec = selinux_msg_msg(msg);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->q_perm.key;
@@ -5681,27 +5583,15 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(&shp->shm_perm, SECCLASS_SHM);
-       if (rc)
-               return rc;
-
-       isec = shp->shm_perm.security;
+       isec = selinux_ipc(&shp->shm_perm);
+       ipc_init_security(isec, SECCLASS_SHM);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(&shp->shm_perm);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_shm_free_security(struct shmid_kernel *shp)
-{
-       ipc_free_security(&shp->shm_perm);
+       return rc;
 }
 
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
@@ -5710,7 +5600,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = shp->shm_perm.security;
+       isec = selinux_ipc(&shp->shm_perm);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->shm_perm.key;
@@ -5774,27 +5664,15 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(&sma->sem_perm, SECCLASS_SEM);
-       if (rc)
-               return rc;
-
-       isec = sma->sem_perm.security;
+       isec = selinux_ipc(&sma->sem_perm);
+       ipc_init_security(isec, SECCLASS_SEM);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(&sma->sem_perm);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_sem_free_security(struct sem_array *sma)
-{
-       ipc_free_security(&sma->sem_perm);
+       return rc;
 }
 
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
@@ -5803,7 +5681,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = sma->sem_perm.security;
+       isec = selinux_ipc(&sma->sem_perm);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->sem_perm.key;
@@ -5886,7 +5764,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 
 static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 {
-       struct ipc_security_struct *isec = ipcp->security;
+       struct ipc_security_struct *isec = selinux_ipc(ipcp);
        *secid = isec->sid;
 }
 
@@ -5905,7 +5783,7 @@ static int selinux_getprocattr(struct task_struct *p,
        unsigned len;
 
        rcu_read_lock();
-       __tsec = __task_cred(p)->security;
+       __tsec = selinux_cred(__task_cred(p));
 
        if (current != p) {
                error = avc_has_perm(current_sid(), __tsec->sid,
@@ -6018,7 +5896,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
           operation.  See selinux_bprm_set_creds for the execve
           checks and may_create for the file creation checks. The
           operation will then fail if the context is not permitted. */
-       tsec = new->security;
+       tsec = selinux_cred(new);
        if (!strcmp(name, "exec")) {
                tsec->exec_sid = sid;
        } else if (!strcmp(name, "fscreate")) {
@@ -6096,7 +5974,7 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
 
 static void selinux_inode_invalidate_secctx(struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
 
        spin_lock(&isec->lock);
        isec->initialized = LABEL_INVALID;
@@ -6108,7 +5986,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode)
  */
 static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
 {
-       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+       int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
+                                          ctx, ctxlen, 0);
+       /* Do not return error when suppressing label (SBLABEL_MNT not set). */
+       return rc == -EOPNOTSUPP ? 0 : rc;
 }
 
 /*
@@ -6135,30 +6016,17 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
                             unsigned long flags)
 {
        const struct task_security_struct *tsec;
-       struct key_security_struct *ksec;
+       struct key_security_struct *ksec = selinux_key(k);
 
-       ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
-       if (!ksec)
-               return -ENOMEM;
-
-       tsec = cred->security;
+       tsec = selinux_cred(cred);
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
                ksec->sid = tsec->sid;
 
-       k->security = ksec;
        return 0;
 }
 
-static void selinux_key_free(struct key *k)
-{
-       struct key_security_struct *ksec = k->security;
-
-       k->security = NULL;
-       kfree(ksec);
-}
-
 static int selinux_key_permission(key_ref_t key_ref,
                                  const struct cred *cred,
                                  unsigned perm)
@@ -6176,14 +6044,14 @@ static int selinux_key_permission(key_ref_t key_ref,
        sid = cred_sid(cred);
 
        key = key_ref_to_ptr(key_ref);
-       ksec = key->security;
+       ksec = selinux_key(key);
 
        return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
 }
 
 static int selinux_key_getsecurity(struct key *key, char **_buffer)
 {
-       struct key_security_struct *ksec = key->security;
+       struct key_security_struct *ksec = selinux_key(key);
        char *context = NULL;
        unsigned len;
        int rc;
@@ -6393,6 +6261,19 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
 }
 #endif
 
+struct lsm_blob_sizes selinux_blob_sizes = {
+       .lbs_cred = sizeof(struct task_security_struct),
+       .lbs_file = sizeof(struct file_security_struct),
+       .lbs_inode = sizeof(struct inode_security_struct),
+       .lbs_ipc = sizeof(struct ipc_security_struct),
+#ifdef CONFIG_KEYS
+       .lbs_key = sizeof(struct key_security_struct),
+#endif /* CONFIG_KEYS */
+       .lbs_msg_msg = sizeof(struct msg_security_struct),
+       .lbs_sock = sizeof(struct sk_security_struct),
+       .lbs_superblock = sizeof(struct superblock_security_struct),
+};
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
        LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6416,7 +6297,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
 
        LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
-       LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
        LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
        LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
        LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
@@ -6461,7 +6341,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(file_permission, selinux_file_permission),
        LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
-       LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
        LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
        LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
        LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
@@ -6475,8 +6354,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(file_open, selinux_file_open),
 
        LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
-       LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
-       LSM_HOOK_INIT(cred_free, selinux_cred_free),
        LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
        LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
@@ -6502,24 +6379,20 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
 
        LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
-       LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
 
        LSM_HOOK_INIT(msg_queue_alloc_security,
                        selinux_msg_queue_alloc_security),
-       LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
        LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
        LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
        LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
        LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
 
        LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
-       LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
        LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
        LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
        LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
 
        LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
-       LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
        LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
        LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
        LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
@@ -6601,7 +6474,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 #ifdef CONFIG_KEYS
        LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
-       LSM_HOOK_INIT(key_free, selinux_key_free),
        LSM_HOOK_INIT(key_permission, selinux_key_permission),
        LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
 #endif
@@ -6626,11 +6498,20 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 static __init int selinux_init(void)
 {
-       if (!security_module_enable("selinux")) {
+       static int finish;
+
+       if (!security_module_enable("selinux",
+                               IS_ENABLED(CONFIG_SECURITY_SELINUX_STACKED))) {
                selinux_enabled = 0;
                return 0;
        }
 
+       if (!finish) {
+               security_add_blobs(&selinux_blob_sizes);
+               finish = 1;
+               return 0;
+       }
+
        if (!selinux_enabled) {
                printk(KERN_INFO "SELinux:  Disabled at boot.\n");
                return 0;
@@ -6643,12 +6524,6 @@ static __init int selinux_init(void)
 
        default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
 
-       sel_inode_cache = kmem_cache_create("selinux_inode_security",
-                                           sizeof(struct inode_security_struct),
-                                           0, SLAB_PANIC, NULL);
-       file_security_cache = kmem_cache_create("selinux_file_security",
-                                           sizeof(struct file_security_struct),
-                                           0, SLAB_PANIC, NULL);
        avc_init();
 
        security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");