Linux 6.9-rc5
[sfrench/cifs-2.6.git] / security / selinux / hooks.c
index a340986aa92e1d9e2434f2aaf5c208930a8156cb..3448454c82d033f7be8a6b942c462c6816360302 100644 (file)
@@ -1,10 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- *  NSA Security-Enhanced Linux (SELinux) security module
+ *  Security-Enhanced Linux (SELinux) security module
  *
  *  This file contains the SELinux hook function implementations.
  *
- *  Authors:  Stephen Smalley, <sds@tycho.nsa.gov>
+ *  Authors:  Stephen Smalley, <stephen.smalley.work@gmail.com>
  *           Chris Vance, <cvance@nai.com>
  *           Wayne Salamon, <wsalamon@nai.com>
  *           James Morris <jmorris@redhat.com>
@@ -24,7 +24,7 @@
 #include <linux/init.h>
 #include <linux/kd.h>
 #include <linux/kernel.h>
-#include <linux/tracehook.h>
+#include <linux/kernel_read_file.h>
 #include <linux/errno.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/task.h>
 #include <linux/export.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#include <uapi/linux/shm.h>
 #include <linux/bpf.h>
 #include <linux/kernfs.h>
 #include <linux/stringhash.h>  /* for hashlen_string() */
 #include <uapi/linux/mount.h>
 #include <linux/fsnotify.h>
 #include <linux/fanotify.h>
+#include <linux/io_uring/cmd.h>
+#include <uapi/linux/lsm.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "audit.h"
 #include "avc_ss.h"
 
+#define SELINUX_INODE_INIT_XATTRS 1
+
 struct selinux_state selinux_state;
 
 /* SECMARK reference count */
@@ -135,17 +140,13 @@ static int __init selinux_enabled_setup(char *str)
 __setup("selinux=", selinux_enabled_setup);
 #endif
 
-static unsigned int selinux_checkreqprot_boot =
-       CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
-
 static int __init checkreqprot_setup(char *str)
 {
        unsigned long checkreqprot;
 
        if (!kstrtoul(str, 0, &checkreqprot)) {
-               selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
                if (checkreqprot)
-                       pr_warn("SELinux: checkreqprot set to 1 via kernel parameter.  This is deprecated and will be rejected in a future kernel release.\n");
+                       pr_err("SELinux: checkreqprot set to 1 via kernel parameter.  This is no longer supported.\n");
        }
        return 1;
 }
@@ -210,10 +211,9 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
  */
 static void cred_init_security(void)
 {
-       struct cred *cred = (struct cred *) current->real_cred;
        struct task_security_struct *tsec;
 
-       tsec = selinux_cred(cred);
+       tsec = selinux_cred(unrcu_pointer(current->real_cred));
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
 }
 
@@ -228,10 +228,35 @@ static inline u32 cred_sid(const struct cred *cred)
        return tsec->sid;
 }
 
+static void __ad_net_init(struct common_audit_data *ad,
+                         struct lsm_network_audit *net,
+                         int ifindex, struct sock *sk, u16 family)
+{
+       ad->type = LSM_AUDIT_DATA_NET;
+       ad->u.net = net;
+       net->netif = ifindex;
+       net->sk = sk;
+       net->family = family;
+}
+
+static void ad_net_init_from_sk(struct common_audit_data *ad,
+                               struct lsm_network_audit *net,
+                               struct sock *sk)
+{
+       __ad_net_init(ad, net, 0, sk, 0);
+}
+
+static void ad_net_init_from_iif(struct common_audit_data *ad,
+                                struct lsm_network_audit *net,
+                                int ifindex, u16 family)
+{
+       __ad_net_init(ad, net, ifindex, NULL, family);
+}
+
 /*
  * get the objective security ID of a task
  */
-static inline u32 task_sid(const struct task_struct *task)
+static inline u32 task_sid_obj(const struct task_struct *task)
 {
        u32 sid;
 
@@ -257,7 +282,7 @@ static int __inode_security_revalidate(struct inode *inode,
 
        might_sleep_if(may_sleep);
 
-       if (selinux_initialized(&selinux_state) &&
+       if (selinux_initialized() &&
            isec->initialized != LABEL_INITIALIZED) {
                if (!may_sleep)
                        return -ECHILD;
@@ -321,7 +346,7 @@ static void inode_free_security(struct inode *inode)
 
        if (!isec)
                return;
-       sbsec = inode->i_sb->s_security;
+       sbsec = selinux_superblock(inode->i_sb);
        /*
         * As not all inode security structures are in a list, we check for
         * empty list outside of the lock to make sure that we won't waste
@@ -339,25 +364,16 @@ static void inode_free_security(struct inode *inode)
        }
 }
 
-static void superblock_free_security(struct super_block *sb)
-{
-       struct superblock_security_struct *sbsec = sb->s_security;
-       sb->s_security = NULL;
-       kfree(sbsec);
-}
-
 struct selinux_mnt_opts {
-       const char *fscontext, *context, *rootcontext, *defcontext;
+       u32 fscontext_sid;
+       u32 context_sid;
+       u32 rootcontext_sid;
+       u32 defcontext_sid;
 };
 
 static void selinux_free_mnt_opts(void *mnt_opts)
 {
-       struct selinux_mnt_opts *opts = mnt_opts;
-       kfree(opts->fscontext);
-       kfree(opts->context);
-       kfree(opts->rootcontext);
-       kfree(opts->defcontext);
-       kfree(opts);
+       kfree(mnt_opts);
 }
 
 enum {
@@ -370,7 +386,7 @@ enum {
 };
 
 #define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
-static struct {
+static const struct {
        const char *name;
        int len;
        int opt;
@@ -412,14 +428,12 @@ static int may_context_mount_sb_relabel(u32 sid,
        const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
 
-       rc = avc_has_perm(&selinux_state,
-                         tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
        if (rc)
                return rc;
 
-       rc = avc_has_perm(&selinux_state,
-                         tsec->sid, sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELTO, NULL);
        return rc;
 }
@@ -430,14 +444,12 @@ static int may_context_mount_inode_relabel(u32 sid,
 {
        const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
-       rc = avc_has_perm(&selinux_state,
-                         tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__RELABELFROM, NULL);
        if (rc)
                return rc;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, sbsec->sid, SECCLASS_FILESYSTEM,
+       rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
                          FILESYSTEM__ASSOCIATE, NULL);
        return rc;
 }
@@ -457,7 +469,7 @@ static int selinux_is_genfs_special_handling(struct super_block *sb)
 
 static int selinux_is_sblabel_mnt(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
        /*
         * IMPORTANT: Double-check logic in this function when adding a new
@@ -483,38 +495,66 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
        }
 }
 
+static int sb_check_xattr_support(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);
+       u32 sid;
+       int rc;
+
+       /*
+        * Make sure that the xattr handler exists and that no
+        * error other than -ENODATA is returned by getxattr on
+        * the root directory.  -ENODATA is ok, as this may be
+        * the first boot of the SELinux kernel before we have
+        * assigned xattr values to the filesystem.
+        */
+       if (!(root_inode->i_opflags & IOP_XATTR)) {
+               pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
+                       sb->s_id, sb->s_type->name);
+               goto fallback;
+       }
+
+       rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
+       if (rc < 0 && rc != -ENODATA) {
+               if (rc == -EOPNOTSUPP) {
+                       pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
+                               sb->s_id, sb->s_type->name);
+                       goto fallback;
+               } else {
+                       pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
+                               sb->s_id, sb->s_type->name, -rc);
+                       return rc;
+               }
+       }
+       return 0;
+
+fallback:
+       /* No xattr support - try to fallback to genfs if possible. */
+       rc = security_genfs_sid(sb->s_type->name, "/",
+                               SECCLASS_DIR, &sid);
+       if (rc)
+               return -EOPNOTSUPP;
+
+       pr_warn("SELinux: (dev %s, type %s) falling back to genfs\n",
+               sb->s_id, sb->s_type->name);
+       sbsec->behavior = SECURITY_FS_USE_GENFS;
+       sbsec->sid = sid;
+       return 0;
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
+       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;
 
        if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
-               /* Make sure that the xattr handler exists and that no
-                  error other than -ENODATA is returned by getxattr on
-                  the root directory.  -ENODATA is ok, as this may be
-                  the first boot of the SELinux kernel before we have
-                  assigned xattr values to the filesystem. */
-               if (!(root_inode->i_opflags & IOP_XATTR)) {
-                       pr_warn("SELinux: (dev %s, type %s) has no "
-                              "xattr support\n", sb->s_id, sb->s_type->name);
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-
-               rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
-               if (rc < 0 && rc != -ENODATA) {
-                       if (rc == -EOPNOTSUPP)
-                               pr_warn("SELinux: (dev %s, type "
-                                      "%s) has no security xattr handler\n",
-                                      sb->s_id, sb->s_type->name);
-                       else
-                               pr_warn("SELinux: (dev %s, type "
-                                      "%s) getxattr errno %d\n", sb->s_id,
-                                      sb->s_type->name, -rc);
-                       goto out;
-               }
+               rc = sb_check_xattr_support(sb);
+               if (rc)
+                       return rc;
        }
 
        sbsec->flags |= SE_SBINITIALIZED;
@@ -553,7 +593,6 @@ static int sb_finish_set_opts(struct super_block *sb)
                spin_lock(&sbsec->isec_lock);
        }
        spin_unlock(&sbsec->isec_lock);
-out:
        return rc;
 }
 
@@ -577,17 +616,6 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
        return 0;
 }
 
-static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
-{
-       int rc = security_context_str_to_sid(&selinux_state, s,
-                                            sid, GFP_KERNEL);
-       if (rc)
-               pr_warn("SELinux: security_context_str_to_sid"
-                      "(%s) failed for (dev %s, type %s) errno=%d\n",
-                      s, sb->s_id, sb->s_type->name, rc);
-       return rc;
-}
-
 /*
  * Allow filesystems with binary mount data to explicitly set mount point
  * labeling information.
@@ -598,21 +626,32 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                                unsigned long *set_kern_flags)
 {
        const struct cred *cred = current_cred();
-       struct superblock_security_struct *sbsec = sb->s_security;
-       struct dentry *root = sbsec->sb->s_root;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
+       struct dentry *root = sb->s_root;
        struct selinux_mnt_opts *opts = mnt_opts;
        struct inode_security_struct *root_isec;
        u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
        u32 defcontext_sid = 0;
        int rc = 0;
 
+       /*
+        * Specifying internal flags without providing a place to
+        * place the results is not allowed
+        */
+       if (kern_flags && !set_kern_flags)
+               return -EINVAL;
+
        mutex_lock(&sbsec->lock);
 
-       if (!selinux_initialized(&selinux_state)) {
+       if (!selinux_initialized()) {
                if (!opts) {
                        /* Defer initialization until selinux_complete_init,
                           after the initial policy is loaded and the security
                           server is ready to handle calls. */
+                       if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+                               sbsec->flags |= SE_SBNATIVE;
+                               *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+                       }
                        goto out;
                }
                rc = -EINVAL;
@@ -620,12 +659,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        "before the security server is initialized\n");
                goto out;
        }
-       if (kern_flags && !set_kern_flags) {
-               /* Specifying internal flags without providing a place to
-                * place the results is not allowed */
-               rc = -EINVAL;
-               goto out;
-       }
 
        /*
         * Binary mount data FS will come through this function twice.  Once
@@ -634,7 +667,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * we need to skip the double mount verification.
         *
         * This does open a hole in which we will not notice if the first
-        * mount using this sb set explict options and a second mount using
+        * mount using this sb set explicit options and a second mount using
         * this sb does not set any security options.  (The first options
         * will be used for both mounts)
         */
@@ -650,37 +683,29 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * than once with different security options.
         */
        if (opts) {
-               if (opts->fscontext) {
-                       rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
-                       if (rc)
-                               goto out;
+               if (opts->fscontext_sid) {
+                       fscontext_sid = opts->fscontext_sid;
                        if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
                                        fscontext_sid))
                                goto out_double_mount;
                        sbsec->flags |= FSCONTEXT_MNT;
                }
-               if (opts->context) {
-                       rc = parse_sid(sb, opts->context, &context_sid);
-                       if (rc)
-                               goto out;
+               if (opts->context_sid) {
+                       context_sid = opts->context_sid;
                        if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
                                        context_sid))
                                goto out_double_mount;
                        sbsec->flags |= CONTEXT_MNT;
                }
-               if (opts->rootcontext) {
-                       rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
-                       if (rc)
-                               goto out;
+               if (opts->rootcontext_sid) {
+                       rootcontext_sid = opts->rootcontext_sid;
                        if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
                                        rootcontext_sid))
                                goto out_double_mount;
                        sbsec->flags |= ROOTCONTEXT_MNT;
                }
-               if (opts->defcontext) {
-                       rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
-                       if (rc)
-                               goto out;
+               if (opts->defcontext_sid) {
+                       defcontext_sid = opts->defcontext_sid;
                        if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
                                        defcontext_sid))
                                goto out_double_mount;
@@ -703,7 +728,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
            !strcmp(sb->s_type->name, "tracefs") ||
            !strcmp(sb->s_type->name, "binder") ||
            !strcmp(sb->s_type->name, "bpf") ||
-           !strcmp(sb->s_type->name, "pstore"))
+           !strcmp(sb->s_type->name, "pstore") ||
+           !strcmp(sb->s_type->name, "securityfs"))
                sbsec->flags |= SE_SBGENFS;
 
        if (!strcmp(sb->s_type->name, "sysfs") ||
@@ -716,7 +742,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                 * Determine the labeling behavior to use for this
                 * filesystem type.
                 */
-               rc = security_fs_use(&selinux_state, sb);
+               rc = security_fs_use(sb);
                if (rc) {
                        pr_warn("%s: security_fs_use(%s) returned %d\n",
                                        __func__, sb->s_type->name, rc);
@@ -732,7 +758,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        if (sb->s_user_ns != &init_user_ns &&
            strcmp(sb->s_type->name, "tmpfs") &&
            strcmp(sb->s_type->name, "ramfs") &&
-           strcmp(sb->s_type->name, "devpts")) {
+           strcmp(sb->s_type->name, "devpts") &&
+           strcmp(sb->s_type->name, "overlay")) {
                if (context_sid || fscontext_sid || rootcontext_sid ||
                    defcontext_sid) {
                        rc = -EACCES;
@@ -740,8 +767,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                }
                if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
                        sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
-                       rc = security_transition_sid(&selinux_state,
-                                                    current_sid(),
+                       rc = security_transition_sid(current_sid(),
                                                     current_sid(),
                                                     SECCLASS_FILE, NULL,
                                                     &sbsec->mntpoint_sid);
@@ -765,7 +791,17 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * sets the label used on all file below the mountpoint, and will set
         * the superblock context if not already set.
         */
-       if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+       if (sbsec->flags & SE_SBNATIVE) {
+               /*
+                * This means we are initializing a superblock that has been
+                * mounted before the SELinux was initialized and the
+                * filesystem requested native labeling. We had already
+                * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
+                * in the original mount attempt, so now we just need to set
+                * the SECURITY_FS_USE_NATIVE behavior.
+                */
+               sbsec->behavior = SECURITY_FS_USE_NATIVE;
+       } else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
                sbsec->behavior = SECURITY_FS_USE_NATIVE;
                *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
        }
@@ -835,8 +871,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;
 
@@ -868,20 +904,14 @@ 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);
        int set_rootcontext =   (oldsbsec->flags & ROOTCONTEXT_MNT);
 
-       /*
-        * if the parent was able to be mounted it clearly had no special lsm
-        * mount options.  thus we can safely deal with this superblock later
-        */
-       if (!selinux_initialized(&selinux_state))
-               return 0;
-
        /*
         * Specifying internal flags without providing a place to
         * place the results is not allowed.
@@ -889,18 +919,31 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        if (kern_flags && !set_kern_flags)
                return -EINVAL;
 
+       mutex_lock(&newsbsec->lock);
+
+       /*
+        * if the parent was able to be mounted it clearly had no special lsm
+        * mount options.  thus we can safely deal with this superblock later
+        */
+       if (!selinux_initialized()) {
+               if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+                       newsbsec->flags |= SE_SBNATIVE;
+                       *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+               }
+               goto out;
+       }
+
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
 
        /* if fs is reusing a sb, make sure that the contexts match */
        if (newsbsec->flags & SE_SBINITIALIZED) {
+               mutex_unlock(&newsbsec->lock);
                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);
-
        newsbsec->flags = oldsbsec->flags;
 
        newsbsec->sid = oldsbsec->sid;
@@ -909,7 +952,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 
        if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
                !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
-               rc = security_fs_use(&selinux_state, newsb);
+               rc = security_fs_use(newsb);
                if (rc)
                        goto out;
        }
@@ -943,85 +986,67 @@ out:
        return rc;
 }
 
+/*
+ * NOTE: the caller is responsible for freeing the memory even if on error.
+ */
 static int selinux_add_opt(int token, const char *s, void **mnt_opts)
 {
        struct selinux_mnt_opts *opts = *mnt_opts;
+       u32 *dst_sid;
+       int rc;
 
-       if (token == Opt_seclabel)      /* eaten and completely ignored */
+       if (token == Opt_seclabel)
+               /* eaten and completely ignored */
                return 0;
+       if (!s)
+               return -EINVAL;
+
+       if (!selinux_initialized()) {
+               pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
+               return -EINVAL;
+       }
 
        if (!opts) {
-               opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
+               opts = kzalloc(sizeof(*opts), GFP_KERNEL);
                if (!opts)
                        return -ENOMEM;
                *mnt_opts = opts;
        }
-       if (!s)
-               return -ENOMEM;
+
        switch (token) {
        case Opt_context:
-               if (opts->context || opts->defcontext)
-                       goto Einval;
-               opts->context = s;
+               if (opts->context_sid || opts->defcontext_sid)
+                       goto err;
+               dst_sid = &opts->context_sid;
                break;
        case Opt_fscontext:
-               if (opts->fscontext)
-                       goto Einval;
-               opts->fscontext = s;
+               if (opts->fscontext_sid)
+                       goto err;
+               dst_sid = &opts->fscontext_sid;
                break;
        case Opt_rootcontext:
-               if (opts->rootcontext)
-                       goto Einval;
-               opts->rootcontext = s;
+               if (opts->rootcontext_sid)
+                       goto err;
+               dst_sid = &opts->rootcontext_sid;
                break;
        case Opt_defcontext:
-               if (opts->context || opts->defcontext)
-                       goto Einval;
-               opts->defcontext = s;
+               if (opts->context_sid || opts->defcontext_sid)
+                       goto err;
+               dst_sid = &opts->defcontext_sid;
                break;
-       }
-       return 0;
-Einval:
-       pr_warn(SEL_MOUNT_FAIL_MSG);
-       return -EINVAL;
-}
-
-static int selinux_add_mnt_opt(const char *option, const char *val, int len,
-                              void **mnt_opts)
-{
-       int token = Opt_error;
-       int rc, i;
-
-       for (i = 0; i < ARRAY_SIZE(tokens); i++) {
-               if (strcmp(option, tokens[i].name) == 0) {
-                       token = tokens[i].opt;
-                       break;
-               }
-       }
-
-       if (token == Opt_error)
+       default:
+               WARN_ON(1);
                return -EINVAL;
-
-       if (token != Opt_seclabel) {
-               val = kmemdup_nul(val, len, GFP_KERNEL);
-               if (!val) {
-                       rc = -ENOMEM;
-                       goto free_opt;
-               }
-       }
-       rc = selinux_add_opt(token, val, mnt_opts);
-       if (unlikely(rc)) {
-               kfree(val);
-               goto free_opt;
        }
+       rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
+       if (rc)
+               pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
+                       s, rc);
        return rc;
 
-free_opt:
-       if (*mnt_opts) {
-               selinux_free_mnt_opts(*mnt_opts);
-               *mnt_opts = NULL;
-       }
-       return rc;
+err:
+       pr_warn(SEL_MOUNT_FAIL_MSG);
+       return -EINVAL;
 }
 
 static int show_sid(struct seq_file *m, u32 sid)
@@ -1030,10 +1055,9 @@ static int show_sid(struct seq_file *m, u32 sid)
        u32 len;
        int rc;
 
-       rc = security_sid_to_context(&selinux_state, sid,
-                                            &context, &len);
+       rc = security_sid_to_context(sid, &context, &len);
        if (!rc) {
-               bool has_comma = context && strchr(context, ',');
+               bool has_comma = strchr(context, ',');
 
                seq_putc(m, '=');
                if (has_comma)
@@ -1048,13 +1072,13 @@ static int show_sid(struct seq_file *m, u32 sid)
 
 static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
        int rc;
 
        if (!(sbsec->flags & SE_SBINITIALIZED))
                return 0;
 
-       if (!selinux_initialized(&selinux_state))
+       if (!selinux_initialized())
                return 0;
 
        if (sbsec->flags & FSCONTEXT_MNT) {
@@ -1079,7 +1103,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
                        return rc;
        }
        if (sbsec->flags & ROOTCONTEXT_MNT) {
-               struct dentry *root = sbsec->sb->s_root;
+               struct dentry *root = sb->s_root;
                struct inode_security_struct *isec = backing_inode_security(root);
                seq_putc(m, ',');
                seq_puts(m, ROOTCONTEXT_STR);
@@ -1119,7 +1143,8 @@ static inline u16 inode_mode_to_security_class(umode_t mode)
 
 static inline int default_protocol_stream(int protocol)
 {
-       return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
+       return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP ||
+               protocol == IPPROTO_MPTCP);
 }
 
 static inline int default_protocol_dgram(int protocol)
@@ -1129,7 +1154,7 @@ static inline int default_protocol_dgram(int protocol)
 
 static inline u16 socket_type_to_security_class(int family, int type, int protocol)
 {
-       int extsockclass = selinux_policycap_extsockclass();
+       bool extsockclass = selinux_policycap_extsockclass();
 
        switch (family) {
        case PF_UNIX:
@@ -1270,7 +1295,9 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                        return SECCLASS_SMC_SOCKET;
                case PF_XDP:
                        return SECCLASS_XDP_SOCKET;
-#if PF_MAX > 45
+               case PF_MCTP:
+                       return SECCLASS_MCTP_SOCKET;
+#if PF_MAX > 46
 #error New address family defined, please update this function.
 #endif
                }
@@ -1305,7 +1332,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
                                path++;
                        }
                }
-               rc = security_genfs_sid(&selinux_state, sb->s_type->name,
+               rc = security_genfs_sid(sb->s_type->name,
                                        path, tclass, sid);
                if (rc == -ENOENT) {
                        /* No match in policy, mark as unlabeled. */
@@ -1360,7 +1387,7 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
                return 0;
        }
 
-       rc = security_context_to_sid_default(&selinux_state, context, rc, sid,
+       rc = security_context_to_sid_default(context, rc, sid,
                                             def_sid, GFP_NOFS);
        if (rc) {
                char *dev = inode->i_sb->s_id;
@@ -1398,7 +1425,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
@@ -1417,8 +1444,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
        spin_unlock(&isec->lock);
 
        switch (sbsec->behavior) {
+       /*
+        * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
+        * via xattr when called from delayed_superblock_init().
+        */
        case SECURITY_FS_USE_NATIVE:
-               break;
        case SECURITY_FS_USE_XATTR:
                if (!(inode->i_opflags & IOP_XATTR)) {
                        sid = sbsec->def_sid;
@@ -1450,7 +1480,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                         * inode_doinit with a dentry, before these inodes could
                         * be used again by userspace.
                         */
-                       goto out;
+                       goto out_invalid;
                }
 
                rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
@@ -1467,7 +1497,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                sid = sbsec->sid;
 
                /* Try to obtain a transition SID. */
-               rc = security_transition_sid(&selinux_state, task_sid, sid,
+               rc = security_transition_sid(task_sid, sid,
                                             sclass, NULL, &sid);
                if (rc)
                        goto out;
@@ -1507,7 +1537,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                         * could be used again by userspace.
                         */
                        if (!dentry)
-                               goto out;
+                               goto out_invalid;
                        rc = selinux_genfs_get_sid(dentry, sclass,
                                                   sbsec->flags, &sid);
                        if (rc) {
@@ -1532,11 +1562,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 out:
        spin_lock(&isec->lock);
        if (isec->initialized == LABEL_PENDING) {
-               if (!sid || rc) {
+               if (rc) {
                        isec->initialized = LABEL_INVALID;
                        goto out_unlock;
                }
-
                isec->initialized = LABEL_INITIALIZED;
                isec->sid = sid;
        }
@@ -1544,6 +1573,15 @@ out:
 out_unlock:
        spin_unlock(&isec->lock);
        return rc;
+
+out_invalid:
+       spin_lock(&isec->lock);
+       if (isec->initialized == LABEL_PENDING) {
+               isec->initialized = LABEL_INVALID;
+               isec->sid = sid;
+       }
+       spin_unlock(&isec->lock);
+       return 0;
 }
 
 /* Convert a Linux signal to an access vector. */
@@ -1604,11 +1642,9 @@ static int cred_has_capability(const struct cred *cred,
                return -EINVAL;
        }
 
-       rc = avc_has_perm_noaudit(&selinux_state,
-                                 sid, sid, sclass, av, 0, &avd);
+       rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
        if (!(opts & CAP_OPT_NOAUDIT)) {
-               int rc2 = avc_audit(&selinux_state,
-                                   sid, sid, sclass, av, &avd, rc, &ad, 0);
+               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
                if (rc2)
                        return rc2;
        }
@@ -1626,16 +1662,13 @@ static int inode_has_perm(const struct cred *cred,
        struct inode_security_struct *isec;
        u32 sid;
 
-       validate_creds(cred);
-
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
        sid = cred_sid(cred);
        isec = selinux_inode(inode);
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, isec->sclass, perms, adp);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1683,7 +1716,7 @@ static inline int file_path_has_perm(const struct cred *cred,
 }
 
 #ifdef CONFIG_BPF_SYSCALL
-static int bpf_fd_pass(struct file *file, u32 sid);
+static int bpf_fd_pass(const struct file *file, u32 sid);
 #endif
 
 /* Check whether a task can use an open file descriptor to
@@ -1708,8 +1741,7 @@ static int file_has_perm(const struct cred *cred,
        ad.u.file = file;
 
        if (sid != fsec->sid) {
-               rc = avc_has_perm(&selinux_state,
-                                 sid, fsec->sid,
+               rc = avc_has_perm(sid, fsec->sid,
                                  SECCLASS_FD,
                                  FD__USE,
                                  &ad);
@@ -1741,7 +1773,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)) {
@@ -1751,7 +1784,7 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
                *_new_isid = tsec->create_sid;
        } else {
                const struct inode_security_struct *dsec = inode_security(dir);
-               return security_transition_sid(&selinux_state, tsec->sid,
+               return security_transition_sid(tsec->sid,
                                               dsec->sid, tclass,
                                               name, _new_isid);
        }
@@ -1772,15 +1805,14 @@ 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;
 
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
                          &ad);
        if (rc)
@@ -1791,13 +1823,11 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, newsid, tclass, FILE__CREATE, &ad);
+       rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
        if (rc)
                return rc;
 
-       return avc_has_perm(&selinux_state,
-                           newsid, sbsec->sid,
+       return avc_has_perm(newsid, sbsec->sid,
                            SECCLASS_FILESYSTEM,
                            FILESYSTEM__ASSOCIATE, &ad);
 }
@@ -1826,8 +1856,7 @@ static int may_link(struct inode *dir,
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
-       rc = avc_has_perm(&selinux_state,
-                         sid, dsec->sid, SECCLASS_DIR, av, &ad);
+       rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
 
@@ -1847,8 +1876,7 @@ static int may_link(struct inode *dir,
                return 0;
        }
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, isec->sclass, av, &ad);
+       rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
        return rc;
 }
 
@@ -1872,19 +1900,16 @@ static inline int may_rename(struct inode *old_dir,
        ad.type = LSM_AUDIT_DATA_DENTRY;
 
        ad.u.dentry = old_dentry;
-       rc = avc_has_perm(&selinux_state,
-                         sid, old_dsec->sid, SECCLASS_DIR,
+       rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
                          DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
                return rc;
-       rc = avc_has_perm(&selinux_state,
-                         sid, old_isec->sid,
+       rc = avc_has_perm(sid, old_isec->sid,
                          old_isec->sclass, FILE__RENAME, &ad);
        if (rc)
                return rc;
        if (old_is_dir && new_dir != old_dir) {
-               rc = avc_has_perm(&selinux_state,
-                                 sid, old_isec->sid,
+               rc = avc_has_perm(sid, old_isec->sid,
                                  old_isec->sclass, DIR__REPARENT, &ad);
                if (rc)
                        return rc;
@@ -1894,15 +1919,13 @@ static inline int may_rename(struct inode *old_dir,
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (d_is_positive(new_dentry))
                av |= DIR__REMOVE_NAME;
-       rc = avc_has_perm(&selinux_state,
-                         sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+       rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
        if (d_is_positive(new_dentry)) {
                new_isec = backing_inode_security(new_dentry);
                new_is_dir = d_is_dir(new_dentry);
-               rc = avc_has_perm(&selinux_state,
-                                 sid, new_isec->sid,
+               rc = avc_has_perm(sid, new_isec->sid,
                                  new_isec->sclass,
                                  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
                if (rc)
@@ -1914,16 +1937,15 @@ static inline int may_rename(struct inode *old_dir,
 
 /* Check whether a task can perform a filesystem operation. */
 static int superblock_has_perm(const struct cred *cred,
-                              struct super_block *sb,
+                              const struct super_block *sb,
                               u32 perms,
                               struct common_audit_data *ad)
 {
        struct superblock_security_struct *sbsec;
        u32 sid = cred_sid(cred);
 
-       sbsec = sb->s_security;
-       return avc_has_perm(&selinux_state,
-                           sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
+       sbsec = selinux_superblock(sb);
+       return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
 }
 
 /* Convert a Linux mode and permission mask to an access vector. */
@@ -1955,7 +1977,7 @@ static inline u32 file_mask_to_av(int mode, int mask)
 }
 
 /* Convert a Linux file to an access vector. */
-static inline u32 file_to_av(struct file *file)
+static inline u32 file_to_av(const struct file *file)
 {
        u32 av = 0;
 
@@ -1978,7 +2000,7 @@ static inline u32 file_to_av(struct file *file)
 }
 
 /*
- * Convert a file to an access vector and include the correct open
+ * Convert a file to an access vector and include the correct
  * open permission.
  */
 static inline u32 open_file_to_av(struct file *file)
@@ -1995,53 +2017,44 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
-static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+static int selinux_binder_set_context_mgr(const struct cred *mgr)
 {
-       u32 mysid = current_sid();
-       u32 mgrsid = task_sid(mgr);
-
-       return avc_has_perm(&selinux_state,
-                           mysid, mgrsid, SECCLASS_BINDER,
+       return avc_has_perm(current_sid(), cred_sid(mgr), SECCLASS_BINDER,
                            BINDER__SET_CONTEXT_MGR, NULL);
 }
 
-static int selinux_binder_transaction(struct task_struct *from,
-                                     struct task_struct *to)
+static int selinux_binder_transaction(const struct cred *from,
+                                     const struct cred *to)
 {
        u32 mysid = current_sid();
-       u32 fromsid = task_sid(from);
-       u32 tosid = task_sid(to);
+       u32 fromsid = cred_sid(from);
+       u32 tosid = cred_sid(to);
        int rc;
 
        if (mysid != fromsid) {
-               rc = avc_has_perm(&selinux_state,
-                                 mysid, fromsid, SECCLASS_BINDER,
+               rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
                                  BINDER__IMPERSONATE, NULL);
                if (rc)
                        return rc;
        }
 
-       return avc_has_perm(&selinux_state,
-                           fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
-                           NULL);
+       return avc_has_perm(fromsid, tosid,
+                           SECCLASS_BINDER, BINDER__CALL, NULL);
 }
 
-static int selinux_binder_transfer_binder(struct task_struct *from,
-                                         struct task_struct *to)
+static int selinux_binder_transfer_binder(const struct cred *from,
+                                         const struct cred *to)
 {
-       u32 fromsid = task_sid(from);
-       u32 tosid = task_sid(to);
-
-       return avc_has_perm(&selinux_state,
-                           fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
+       return avc_has_perm(cred_sid(from), cred_sid(to),
+                           SECCLASS_BINDER, BINDER__TRANSFER,
                            NULL);
 }
 
-static int selinux_binder_transfer_file(struct task_struct *from,
-                                       struct task_struct *to,
-                                       struct file *file)
+static int selinux_binder_transfer_file(const struct cred *from,
+                                       const struct cred *to,
+                                       const struct file *file)
 {
-       u32 sid = task_sid(to);
+       u32 sid = cred_sid(to);
        struct file_security_struct *fsec = selinux_file(file);
        struct dentry *dentry = file->f_path.dentry;
        struct inode_security_struct *isec;
@@ -2052,8 +2065,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
        ad.u.path = file->f_path;
 
        if (sid != fsec->sid) {
-               rc = avc_has_perm(&selinux_state,
-                                 sid, fsec->sid,
+               rc = avc_has_perm(sid, fsec->sid,
                                  SECCLASS_FD,
                                  FD__USE,
                                  &ad);
@@ -2071,38 +2083,35 @@ static int selinux_binder_transfer_file(struct task_struct *from,
                return 0;
 
        isec = backing_inode_security(dentry);
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, isec->sclass, file_to_av(file),
+       return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
                            &ad);
 }
 
 static int selinux_ptrace_access_check(struct task_struct *child,
-                                    unsigned int mode)
+                                      unsigned int mode)
 {
        u32 sid = current_sid();
-       u32 csid = task_sid(child);
+       u32 csid = task_sid_obj(child);
 
        if (mode & PTRACE_MODE_READ)
-               return avc_has_perm(&selinux_state,
-                                   sid, csid, SECCLASS_FILE, FILE__READ, NULL);
+               return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ,
+                               NULL);
 
-       return avc_has_perm(&selinux_state,
-                           sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
+       return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE,
+                       NULL);
 }
 
 static int selinux_ptrace_traceme(struct task_struct *parent)
 {
-       return avc_has_perm(&selinux_state,
-                           task_sid(parent), current_sid(), SECCLASS_PROCESS,
-                           PROCESS__PTRACE, NULL);
+       return avc_has_perm(task_sid_obj(parent), task_sid_obj(current),
+                           SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
 }
 
-static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
+static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(target), SECCLASS_PROCESS,
-                           PROCESS__GETCAP, NULL);
+       return avc_has_perm(current_sid(), task_sid_obj(target),
+                       SECCLASS_PROCESS, PROCESS__GETCAP, NULL);
 }
 
 static int selinux_capset(struct cred *new, const struct cred *old,
@@ -2110,8 +2119,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
                          const kernel_cap_t *inheritable,
                          const kernel_cap_t *permitted)
 {
-       return avc_has_perm(&selinux_state,
-                           cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
+       return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
                            PROCESS__SETCAP, NULL);
 }
 
@@ -2131,7 +2139,7 @@ static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
        return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
 }
 
-static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
+static int selinux_quotactl(int cmds, int type, int id, const struct super_block *sb)
 {
        const struct cred *cred = current_cred();
        int rc = 0;
@@ -2178,21 +2186,18 @@ static int selinux_syslog(int type)
        switch (type) {
        case SYSLOG_ACTION_READ_ALL:    /* Read last kernel messages */
        case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), SECINITSID_KERNEL,
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                                    SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
        case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
        case SYSLOG_ACTION_CONSOLE_ON:  /* Enable logging to console */
        /* Set level of messages printed to console */
        case SYSLOG_ACTION_CONSOLE_LEVEL:
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), SECINITSID_KERNEL,
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                                    SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
                                    NULL);
        }
        /* All other syslog types */
-       return avc_has_perm(&selinux_state,
-                           current_sid(), SECINITSID_KERNEL,
+       return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                            SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
 }
 
@@ -2226,7 +2231,7 @@ static u32 ptrace_parent_sid(void)
        rcu_read_lock();
        tracer = ptrace_parent(current);
        if (tracer)
-               sid = task_sid(tracer);
+               sid = task_sid_obj(tracer);
        rcu_read_unlock();
 
        return sid;
@@ -2259,8 +2264,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
                        av |= PROCESS2__NNP_TRANSITION;
                if (nosuid)
                        av |= PROCESS2__NOSUID_TRANSITION;
-               rc = avc_has_perm(&selinux_state,
-                                 old_tsec->sid, new_tsec->sid,
+               rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
                                  SECCLASS_PROCESS2, av, NULL);
                if (!rc)
                        return 0;
@@ -2271,7 +2275,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
         * i.e. SIDs that are guaranteed to only be allowed a subset
         * of the permissions of the current SID.
         */
-       rc = security_bounded_transition(&selinux_state, old_tsec->sid,
+       rc = security_bounded_transition(old_tsec->sid,
                                         new_tsec->sid);
        if (!rc)
                return 0;
@@ -2311,6 +2315,19 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
        new_tsec->keycreate_sid = 0;
        new_tsec->sockcreate_sid = 0;
 
+       /*
+        * Before policy is loaded, label any task outside kernel space
+        * as SECINITSID_INIT, so that any userspace tasks surviving from
+        * early boot end up with a label different from SECINITSID_KERNEL
+        * (if the policy chooses to set SECINITSID_INIT != SECINITSID_KERNEL).
+        */
+       if (!selinux_initialized()) {
+               new_tsec->sid = SECINITSID_INIT;
+               /* also clear the exec_sid just in case */
+               new_tsec->exec_sid = 0;
+               return 0;
+       }
+
        if (old_tsec->exec_sid) {
                new_tsec->sid = old_tsec->exec_sid;
                /* Reset exec SID on execve. */
@@ -2322,7 +2339,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
                        return rc;
        } else {
                /* Check for a default transition on this program. */
-               rc = security_transition_sid(&selinux_state, old_tsec->sid,
+               rc = security_transition_sid(old_tsec->sid,
                                             isec->sid, SECCLASS_PROCESS, NULL,
                                             &new_tsec->sid);
                if (rc)
@@ -2341,29 +2358,25 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
        ad.u.file = bprm->file;
 
        if (new_tsec->sid == old_tsec->sid) {
-               rc = avc_has_perm(&selinux_state,
-                                 old_tsec->sid, isec->sid,
+               rc = avc_has_perm(old_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
                if (rc)
                        return rc;
        } else {
                /* Check permissions for the transition. */
-               rc = avc_has_perm(&selinux_state,
-                                 old_tsec->sid, new_tsec->sid,
+               rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
                                  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
                if (rc)
                        return rc;
 
-               rc = avc_has_perm(&selinux_state,
-                                 new_tsec->sid, isec->sid,
+               rc = avc_has_perm(new_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
                if (rc)
                        return rc;
 
                /* Check for shared state */
                if (bprm->unsafe & LSM_UNSAFE_SHARE) {
-                       rc = avc_has_perm(&selinux_state,
-                                         old_tsec->sid, new_tsec->sid,
+                       rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
                                          SECCLASS_PROCESS, PROCESS__SHARE,
                                          NULL);
                        if (rc)
@@ -2375,8 +2388,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
                if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
                        u32 ptsid = ptrace_parent_sid();
                        if (ptsid != 0) {
-                               rc = avc_has_perm(&selinux_state,
-                                                 ptsid, new_tsec->sid,
+                               rc = avc_has_perm(ptsid, new_tsec->sid,
                                                  SECCLASS_PROCESS,
                                                  PROCESS__PTRACE, NULL);
                                if (rc)
@@ -2390,8 +2402,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
                /* Enable secure mode for SIDs transitions unless
                   the noatsecure permission is granted between
                   the two SIDs, i.e. ahp returns 0. */
-               rc = avc_has_perm(&selinux_state,
-                                 old_tsec->sid, new_tsec->sid,
+               rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
                                  SECCLASS_PROCESS, PROCESS__NOATSECURE,
                                  NULL);
                bprm->secureexec |= !!rc;
@@ -2457,7 +2468,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 /*
  * Prepare a process for imminent new credential changes due to exec
  */
-static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
+static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
 {
        struct task_security_struct *new_tsec;
        struct rlimit *rlim, *initrlim;
@@ -2483,8 +2494,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
         * higher than the default soft limit for cases where the default is
         * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
         */
-       rc = avc_has_perm(&selinux_state,
-                         new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+       rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
                          PROCESS__RLIMITINH, NULL);
        if (rc) {
                /* protect against do_prlimit() */
@@ -2504,7 +2514,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
  * Clean up the process immediately after the installation of new credentials
  * due to exec
  */
-static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
+static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
 {
        const struct task_security_struct *tsec = selinux_cred(current_cred());
        u32 osid, sid;
@@ -2523,12 +2533,11 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
         * This must occur _after_ the task SID has been updated so that any
         * kill done after the flush will be checked against the new SID.
         */
-       rc = avc_has_perm(&selinux_state,
-                         osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
+       rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
        if (rc) {
                clear_itimer();
 
-               spin_lock_irq(&current->sighand->siglock);
+               spin_lock_irq(&unrcu_pointer(current->sighand)->siglock);
                if (!fatal_signal_pending(current)) {
                        flush_sigqueue(&current->pending);
                        flush_sigqueue(&current->signal->shared_pending);
@@ -2536,13 +2545,13 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
                        sigemptyset(&current->blocked);
                        recalc_sigpending();
                }
-               spin_unlock_irq(&current->sighand->siglock);
+               spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
        }
 
        /* Wake up the parent if it is waiting so that it can recheck
         * wait permission to the new task SID. */
        read_lock(&tasklist_lock);
-       __wake_up_parent(current, current->real_parent);
+       __wake_up_parent(current, unrcu_pointer(current->real_parent));
        read_unlock(&tasklist_lock);
 }
 
@@ -2550,29 +2559,18 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 
 static int selinux_sb_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);
        spin_lock_init(&sbsec->isec_lock);
-       sbsec->sb = sb;
        sbsec->sid = SECINITSID_UNLABELED;
        sbsec->def_sid = SECINITSID_FILE;
        sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-       sb->s_security = sbsec;
 
        return 0;
 }
 
-static void selinux_sb_free_security(struct super_block *sb)
-{
-       superblock_free_security(sb);
-}
-
 static inline int opt_len(const char *s)
 {
        bool open_quote = false;
@@ -2619,8 +2617,9 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
                                }
                        }
                        rc = selinux_add_opt(token, arg, mnt_opts);
+                       kfree(arg);
+                       arg = NULL;
                        if (unlikely(rc)) {
-                               kfree(arg);
                                goto free_opt;
                        }
                } else {
@@ -2648,12 +2647,55 @@ free_opt:
        return rc;
 }
 
+static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
+{
+       struct selinux_mnt_opts *opts = mnt_opts;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
+
+       /*
+        * Superblock not initialized (i.e. no options) - reject if any
+        * options specified, otherwise accept.
+        */
+       if (!(sbsec->flags & SE_SBINITIALIZED))
+               return opts ? 1 : 0;
+
+       /*
+        * Superblock initialized and no options specified - reject if
+        * superblock has any options set, otherwise accept.
+        */
+       if (!opts)
+               return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
+
+       if (opts->fscontext_sid) {
+               if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+                              opts->fscontext_sid))
+                       return 1;
+       }
+       if (opts->context_sid) {
+               if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+                              opts->context_sid))
+                       return 1;
+       }
+       if (opts->rootcontext_sid) {
+               struct inode_security_struct *root_isec;
+
+               root_isec = backing_inode_security(sb->s_root);
+               if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+                              opts->rootcontext_sid))
+                       return 1;
+       }
+       if (opts->defcontext_sid) {
+               if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+                              opts->defcontext_sid))
+                       return 1;
+       }
+       return 0;
+}
+
 static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
 {
        struct selinux_mnt_opts *opts = mnt_opts;
-       struct superblock_security_struct *sbsec = sb->s_security;
-       u32 sid;
-       int rc;
+       struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
        if (!(sbsec->flags & SE_SBINITIALIZED))
                return 0;
@@ -2661,34 +2703,26 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
        if (!opts)
                return 0;
 
-       if (opts->fscontext) {
-               rc = parse_sid(sb, opts->fscontext, &sid);
-               if (rc)
-                       return rc;
-               if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+       if (opts->fscontext_sid) {
+               if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+                              opts->fscontext_sid))
                        goto out_bad_option;
        }
-       if (opts->context) {
-               rc = parse_sid(sb, opts->context, &sid);
-               if (rc)
-                       return rc;
-               if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+       if (opts->context_sid) {
+               if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+                              opts->context_sid))
                        goto out_bad_option;
        }
-       if (opts->rootcontext) {
+       if (opts->rootcontext_sid) {
                struct inode_security_struct *root_isec;
                root_isec = backing_inode_security(sb->s_root);
-               rc = parse_sid(sb, opts->rootcontext, &sid);
-               if (rc)
-                       return rc;
-               if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+               if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+                              opts->rootcontext_sid))
                        goto out_bad_option;
        }
-       if (opts->defcontext) {
-               rc = parse_sid(sb, opts->defcontext, &sid);
-               if (rc)
-                       return rc;
-               if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+       if (opts->defcontext_sid) {
+               if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+                              opts->defcontext_sid))
                        goto out_bad_option;
        }
        return 0;
@@ -2700,7 +2734,7 @@ out_bad_option:
        return -EINVAL;
 }
 
-static int selinux_sb_kern_mount(struct super_block *sb)
+static int selinux_sb_kern_mount(const struct super_block *sb)
 {
        const struct cred *cred = current_cred();
        struct common_audit_data ad;
@@ -2751,44 +2785,45 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
                                   FILESYSTEM__UNMOUNT, NULL);
 }
 
-static int selinux_fs_context_dup(struct fs_context *fc,
-                                 struct fs_context *src_fc)
+static int selinux_fs_context_submount(struct fs_context *fc,
+                                  struct super_block *reference)
 {
-       const struct selinux_mnt_opts *src = src_fc->security;
+       const struct superblock_security_struct *sbsec = selinux_superblock(reference);
        struct selinux_mnt_opts *opts;
 
-       if (!src)
+       /*
+        * Ensure that fc->security remains NULL when no options are set
+        * as expected by selinux_set_mnt_opts().
+        */
+       if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
                return 0;
 
-       fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
-       if (!fc->security)
+       opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+       if (!opts)
                return -ENOMEM;
 
-       opts = fc->security;
-
-       if (src->fscontext) {
-               opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
-               if (!opts->fscontext)
-                       return -ENOMEM;
-       }
-       if (src->context) {
-               opts->context = kstrdup(src->context, GFP_KERNEL);
-               if (!opts->context)
-                       return -ENOMEM;
-       }
-       if (src->rootcontext) {
-               opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
-               if (!opts->rootcontext)
-                       return -ENOMEM;
-       }
-       if (src->defcontext) {
-               opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
-               if (!opts->defcontext)
-                       return -ENOMEM;
-       }
+       if (sbsec->flags & FSCONTEXT_MNT)
+               opts->fscontext_sid = sbsec->sid;
+       if (sbsec->flags & CONTEXT_MNT)
+               opts->context_sid = sbsec->mntpoint_sid;
+       if (sbsec->flags & DEFCONTEXT_MNT)
+               opts->defcontext_sid = sbsec->def_sid;
+       fc->security = opts;
        return 0;
 }
 
+static int selinux_fs_context_dup(struct fs_context *fc,
+                                 struct fs_context *src_fc)
+{
+       const struct selinux_mnt_opts *src = src_fc->security;
+
+       if (!src)
+               return 0;
+
+       fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
+       return fc->security ? 0 : -ENOMEM;
+}
+
 static const struct fs_parameter_spec selinux_fs_parameters[] = {
        fsparam_string(CONTEXT_STR,     Opt_context),
        fsparam_string(DEFCONTEXT_STR,  Opt_defcontext),
@@ -2802,18 +2837,13 @@ static int selinux_fs_context_parse_param(struct fs_context *fc,
                                          struct fs_parameter *param)
 {
        struct fs_parse_result result;
-       int opt, rc;
+       int opt;
 
        opt = fs_parse(fc, selinux_fs_parameters, param, &result);
        if (opt < 0)
                return opt;
 
-       rc = selinux_add_opt(opt, param->string, &fc->security);
-       if (!rc) {
-               param->string = NULL;
-               rc = 1;
-       }
-       return rc;
+       return selinux_add_opt(opt, param->string, &fc->security);
 }
 
 /* inode security operations */
@@ -2840,7 +2870,8 @@ static void selinux_inode_free_security(struct inode *inode)
 }
 
 static int selinux_dentry_init_security(struct dentry *dentry, int mode,
-                                       const struct qstr *name, void **ctx,
+                                       const struct qstr *name,
+                                       const char **xattr_name, void **ctx,
                                        u32 *ctxlen)
 {
        u32 newsid;
@@ -2853,7 +2884,10 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
        if (rc)
                return rc;
 
-       return security_sid_to_context(&selinux_state, newsid, (char **)ctx,
+       if (xattr_name)
+               *xattr_name = XATTR_NAME_SELINUX;
+
+       return security_sid_to_context(newsid, (char **)ctx,
                                       ctxlen);
 }
 
@@ -2880,52 +2914,104 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
 
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       const struct qstr *qstr,
-                                      const char **name,
-                                      void **value, size_t *len)
+                                      struct xattr *xattrs, int *xattr_count)
 {
        const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct superblock_security_struct *sbsec;
+       struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
        u32 newsid, clen;
+       u16 newsclass;
        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(tsec, dir, qstr,
-               inode_mode_to_security_class(inode->i_mode),
-               &newsid);
+       newsclass = inode_mode_to_security_class(inode->i_mode);
+       rc = selinux_determine_inode_label(tsec, dir, qstr, newsclass, &newsid);
        if (rc)
                return rc;
 
        /* Possibly defer initialization to selinux_complete_init. */
        if (sbsec->flags & SE_SBINITIALIZED) {
                struct inode_security_struct *isec = selinux_inode(inode);
-               isec->sclass = inode_mode_to_security_class(inode->i_mode);
+               isec->sclass = newsclass;
                isec->sid = newsid;
                isec->initialized = LABEL_INITIALIZED;
        }
 
-       if (!selinux_initialized(&selinux_state) ||
+       if (!selinux_initialized() ||
            !(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
-       if (name)
-               *name = XATTR_SELINUX_SUFFIX;
-
-       if (value && len) {
-               rc = security_sid_to_context_force(&selinux_state, newsid,
+       if (xattr) {
+               rc = security_sid_to_context_force(newsid,
                                                   &context, &clen);
                if (rc)
                        return rc;
-               *value = context;
-               *len = clen;
+               xattr->value = context;
+               xattr->value_len = clen;
+               xattr->name = XATTR_SELINUX_SUFFIX;
        }
 
        return 0;
 }
 
+static int selinux_inode_init_security_anon(struct inode *inode,
+                                           const struct qstr *name,
+                                           const struct inode *context_inode)
+{
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
+       struct common_audit_data ad;
+       struct inode_security_struct *isec;
+       int rc;
+
+       if (unlikely(!selinux_initialized()))
+               return 0;
+
+       isec = selinux_inode(inode);
+
+       /*
+        * We only get here once per ephemeral inode.  The inode has
+        * been initialized via inode_alloc_security but is otherwise
+        * untouched.
+        */
+
+       if (context_inode) {
+               struct inode_security_struct *context_isec =
+                       selinux_inode(context_inode);
+               if (context_isec->initialized != LABEL_INITIALIZED) {
+                       pr_err("SELinux:  context_inode is not initialized\n");
+                       return -EACCES;
+               }
+
+               isec->sclass = context_isec->sclass;
+               isec->sid = context_isec->sid;
+       } else {
+               isec->sclass = SECCLASS_ANON_INODE;
+               rc = security_transition_sid(
+                       tsec->sid, tsec->sid,
+                       isec->sclass, name, &isec->sid);
+               if (rc)
+                       return rc;
+       }
+
+       isec->initialized = LABEL_INITIALIZED;
+       /*
+        * Now that we've initialized security, check whether we're
+        * allowed to actually create this type of anonymous inode.
+        */
+
+       ad.type = LSM_AUDIT_DATA_ANONINODE;
+       ad.u.anonclass = name ? (const char *)name->name : "?";
+
+       return avc_has_perm(tsec->sid,
+                           isec->sid,
+                           isec->sclass,
+                           FILE__CREATE,
+                           &ad);
+}
+
 static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        return may_create(dir, dentry, SECCLASS_FILE);
@@ -2982,8 +3068,6 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        struct inode_security_struct *isec;
        u32 sid;
 
-       validate_creds(cred);
-
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
        sid = cred_sid(cred);
@@ -2991,9 +3075,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        if (IS_ERR(isec))
                return PTR_ERR(isec);
 
-       return avc_has_perm_flags(&selinux_state,
-                                 sid, isec->sid, isec->sclass, FILE__READ, &ad,
-                                 rcu ? MAY_NOT_BLOCK : 0);
+       return avc_has_perm(sid, isec->sid, isec->sclass, FILE__READ, &ad);
 }
 
 static noinline int audit_inode_permission(struct inode *inode,
@@ -3002,17 +3084,12 @@ static noinline int audit_inode_permission(struct inode *inode,
 {
        struct common_audit_data ad;
        struct inode_security_struct *isec = selinux_inode(inode);
-       int rc;
 
        ad.type = LSM_AUDIT_DATA_INODE;
        ad.u.inode = inode;
 
-       rc = slow_avc_audit(&selinux_state,
-                           current_sid(), isec->sid, isec->sclass, perms,
+       return slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
                            audited, denied, result, &ad);
-       if (rc)
-               return rc;
-       return 0;
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
@@ -3034,8 +3111,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (!mask)
                return 0;
 
-       validate_creds(cred);
-
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -3046,9 +3121,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (IS_ERR(isec))
                return PTR_ERR(isec);
 
-       rc = avc_has_perm_noaudit(&selinux_state,
-                                 sid, isec->sid, isec->sclass, perms,
-                                 no_block ? AVC_NONBLOCKING : 0,
+       rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0,
                                  &avd);
        audited = avc_audit_required(perms, &avd, rc,
                                     from_access ? FILE__AUDIT_ACCESS : 0,
@@ -3056,17 +3129,14 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (likely(!audited))
                return rc;
 
-       /* fall back to ref-walk if we have to generate audit */
-       if (no_block)
-               return -ECHILD;
-
        rc2 = audit_inode_permission(inode, perms, audited, denied, rc);
        if (rc2)
                return rc2;
        return rc;
 }
 
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+                                struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
        struct inode *inode = d_backing_inode(dentry);
@@ -3111,7 +3181,8 @@ static bool has_cap_mac_admin(bool audit)
        return true;
 }
 
-static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
+static int selinux_inode_setxattr(struct mnt_idmap *idmap,
+                                 struct dentry *dentry, const char *name,
                                  const void *value, size_t size, int flags)
 {
        struct inode *inode = d_backing_inode(dentry);
@@ -3131,27 +3202,26 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
        }
 
-       if (!selinux_initialized(&selinux_state))
-               return (inode_owner_or_capable(inode) ? 0 : -EPERM);
+       if (!selinux_initialized())
+               return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
 
-       sbsec = inode->i_sb->s_security;
+       sbsec = selinux_superblock(inode->i_sb);
        if (!(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
-       if (!inode_owner_or_capable(inode))
+       if (!inode_owner_or_capable(idmap, inode))
                return -EPERM;
 
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
 
        isec = backing_inode_security(dentry);
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, isec->sclass,
+       rc = avc_has_perm(sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
        if (rc)
                return rc;
 
-       rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+       rc = security_context_to_sid(value, size, &newsid,
                                     GFP_KERNEL);
        if (rc == -EINVAL) {
                if (!has_cap_mac_admin(true)) {
@@ -3172,37 +3242,56 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                        }
                        ab = audit_log_start(audit_context(),
                                             GFP_ATOMIC, AUDIT_SELINUX_ERR);
+                       if (!ab)
+                               return rc;
                        audit_log_format(ab, "op=setxattr invalid_context=");
                        audit_log_n_untrustedstring(ab, value, audit_size);
                        audit_log_end(ab);
 
                        return rc;
                }
-               rc = security_context_to_sid_force(&selinux_state, value,
+               rc = security_context_to_sid_force(value,
                                                   size, &newsid);
        }
        if (rc)
                return rc;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, newsid, isec->sclass,
+       rc = avc_has_perm(sid, newsid, isec->sclass,
                          FILE__RELABELTO, &ad);
        if (rc)
                return rc;
 
-       rc = security_validate_transition(&selinux_state, isec->sid, newsid,
+       rc = security_validate_transition(isec->sid, newsid,
                                          sid, isec->sclass);
        if (rc)
                return rc;
 
-       return avc_has_perm(&selinux_state,
-                           newsid,
+       return avc_has_perm(newsid,
                            sbsec->sid,
                            SECCLASS_FILESYSTEM,
                            FILESYSTEM__ASSOCIATE,
                            &ad);
 }
 
+static int selinux_inode_set_acl(struct mnt_idmap *idmap,
+                                struct dentry *dentry, const char *acl_name,
+                                struct posix_acl *kacl)
+{
+       return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
+static int selinux_inode_get_acl(struct mnt_idmap *idmap,
+                                struct dentry *dentry, const char *acl_name)
+{
+       return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
+}
+
+static int selinux_inode_remove_acl(struct mnt_idmap *idmap,
+                                   struct dentry *dentry, const char *acl_name)
+{
+       return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
 static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
                                        const void *value, size_t size,
                                        int flags)
@@ -3217,7 +3306,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
                return;
        }
 
-       if (!selinux_initialized(&selinux_state)) {
+       if (!selinux_initialized()) {
                /* If we haven't even been initialized, then we can't validate
                 * against a policy, so leave the label as invalid. It may
                 * resolve to a valid label on the next revalidation try if
@@ -3226,7 +3315,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
                return;
        }
 
-       rc = security_context_to_sid_force(&selinux_state, value, size,
+       rc = security_context_to_sid_force(value, size,
                                           &newsid);
        if (rc) {
                pr_err("SELinux:  unable to map context to SID"
@@ -3241,8 +3330,6 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
        isec->sid = newsid;
        isec->initialized = LABEL_INITIALIZED;
        spin_unlock(&isec->lock);
-
-       return;
 }
 
 static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
@@ -3259,10 +3346,11 @@ static int selinux_inode_listxattr(struct dentry *dentry)
        return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
+static int selinux_inode_removexattr(struct mnt_idmap *idmap,
+                                    struct dentry *dentry, const char *name)
 {
        if (strcmp(name, XATTR_NAME_SELINUX)) {
-               int rc = cap_inode_removexattr(dentry, name);
+               int rc = cap_inode_removexattr(idmap, dentry, name);
                if (rc)
                        return rc;
 
@@ -3271,6 +3359,9 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
                return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
        }
 
+       if (!selinux_initialized())
+               return 0;
+
        /* No one is allowed to remove a SELinux security label.
           You can change the label, but all data must be labeled. */
        return -EACCES;
@@ -3325,7 +3416,9 @@ static int selinux_path_notify(const struct path *path, u64 mask,
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
+static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
+                                    struct inode *inode, const char *name,
+                                    void **buffer, bool alloc)
 {
        u32 size;
        int error;
@@ -3336,7 +3429,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
         * If we're not initialized yet, then we can't validate contexts, so
         * just let vfs_getxattr fall back to using the on-disk xattr.
         */
-       if (!selinux_initialized(&selinux_state) ||
+       if (!selinux_initialized() ||
            strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
@@ -3351,11 +3444,10 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
         */
        isec = inode_security(inode);
        if (has_cap_mac_admin(false))
-               error = security_sid_to_context_force(&selinux_state,
-                                                     isec->sid, &context,
+               error = security_sid_to_context_force(isec->sid, &context,
                                                      &size);
        else
-               error = security_sid_to_context(&selinux_state, isec->sid,
+               error = security_sid_to_context(isec->sid,
                                                &context, &size);
        if (error)
                return error;
@@ -3373,20 +3465,21 @@ 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;
+       struct superblock_security_struct *sbsec;
        u32 newsid;
        int rc;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
+       sbsec = selinux_superblock(inode->i_sb);
        if (!(sbsec->flags & SBLABEL_MNT))
                return -EOPNOTSUPP;
 
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+       rc = security_context_to_sid(value, size, &newsid,
                                     GFP_KERNEL);
        if (rc)
                return rc;
@@ -3402,6 +3495,10 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
 {
        const int len = sizeof(XATTR_NAME_SELINUX);
+
+       if (!selinux_initialized())
+               return 0;
+
        if (buffer && len <= buffer_size)
                memcpy(buffer, XATTR_NAME_SELINUX, len);
        return len;
@@ -3437,9 +3534,10 @@ static int selinux_inode_copy_up_xattr(const char *name)
 {
        /* The copy_up hook above sets the initial context on an inode, but we
         * don't then want to overwrite it by blindly copying all the lower
-        * xattrs up.  Instead, we have to filter out SELinux-related xattrs.
+        * xattrs up.  Instead, filter out SELinux-related xattrs following
+        * policy load.
         */
-       if (strcmp(name, XATTR_NAME_SELINUX) == 0)
+       if (selinux_initialized() && strcmp(name, XATTR_NAME_SELINUX) == 0)
                return 1; /* Discard */
        /*
         * Any other attribute apart from SELINUX is not claimed, supported
@@ -3475,7 +3573,7 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
                return rc;
        }
 
-       rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid,
+       rc = security_context_to_sid(context, clen, &parent_sid,
                                     GFP_KERNEL);
        kfree(context);
        if (rc)
@@ -3490,14 +3588,14 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
                q.name = kn->name;
                q.hash_len = hashlen_string(kn_dir, kn->name);
 
-               rc = security_transition_sid(&selinux_state, tsec->sid,
+               rc = security_transition_sid(tsec->sid,
                                             parent_sid, secclass, &q,
                                             &newsid);
                if (rc)
                        return rc;
        }
 
-       rc = security_sid_to_context_force(&selinux_state, newsid,
+       rc = security_sid_to_context_force(newsid,
                                           &context, &clen);
        if (rc)
                return rc;
@@ -3537,7 +3635,7 @@ static int selinux_file_permission(struct file *file, int mask)
 
        isec = inode_security(inode);
        if (sid == fsec->sid && fsec->isid == isec->sid &&
-           fsec->pseqno == avc_policy_seqno(&selinux_state))
+           fsec->pseqno == avc_policy_seqno())
                /* No change since file_open check. */
                return 0;
 
@@ -3578,8 +3676,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
        ad.u.op->path = file->f_path;
 
        if (ssid != fsec->sid) {
-               rc = avc_has_perm(&selinux_state,
-                                 ssid, fsec->sid,
+               rc = avc_has_perm(ssid, fsec->sid,
                                SECCLASS_FD,
                                FD__USE,
                                &ad);
@@ -3591,8 +3688,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
                return 0;
 
        isec = inode_security(inode);
-       rc = avc_has_extended_perms(&selinux_state,
-                                   ssid, isec->sid, isec->sclass,
+       rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
                                    requested, driver, xperm, &ad);
 out:
        return rc;
@@ -3630,6 +3726,12 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                                            CAP_OPT_NONE, true);
                break;
 
+       case FIOCLEX:
+       case FIONCLEX:
+               if (!selinux_policycap_ioctl_skip_cloexec())
+                       error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+               break;
+
        /* default case assumes that the command will go
         * to the file's ioctl() function.
         */
@@ -3639,6 +3741,33 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        return error;
 }
 
+static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       /*
+        * If we are in a 64-bit kernel running 32-bit userspace, we need to
+        * make sure we don't compare 32-bit flags to 64-bit flags.
+        */
+       switch (cmd) {
+       case FS_IOC32_GETFLAGS:
+               cmd = FS_IOC_GETFLAGS;
+               break;
+       case FS_IOC32_SETFLAGS:
+               cmd = FS_IOC_SETFLAGS;
+               break;
+       case FS_IOC32_GETVERSION:
+               cmd = FS_IOC_GETVERSION;
+               break;
+       case FS_IOC32_SETVERSION:
+               cmd = FS_IOC_SETVERSION;
+               break;
+       default:
+               break;
+       }
+
+       return selinux_file_ioctl(file, cmd, arg);
+}
+
 static int default_noexec __ro_after_init;
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
@@ -3655,8 +3784,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                 * private file mapping that will also be writable.
                 * This has an additional check.
                 */
-               rc = avc_has_perm(&selinux_state,
-                                 sid, sid, SECCLASS_PROCESS,
+               rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
                                  PROCESS__EXECMEM, NULL);
                if (rc)
                        goto error;
@@ -3686,15 +3814,15 @@ static int selinux_mmap_addr(unsigned long addr)
 
        if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
                u32 sid = current_sid();
-               rc = avc_has_perm(&selinux_state,
-                                 sid, sid, SECCLASS_MEMPROTECT,
+               rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
                                  MEMPROTECT__MMAP_ZERO, NULL);
        }
 
        return rc;
 }
 
-static int selinux_mmap_file(struct file *file, unsigned long reqprot,
+static int selinux_mmap_file(struct file *file,
+                            unsigned long reqprot __always_unused,
                             unsigned long prot, unsigned long flags)
 {
        struct common_audit_data ad;
@@ -3709,37 +3837,26 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot,
                        return rc;
        }
 
-       if (selinux_state.checkreqprot)
-               prot = reqprot;
-
        return file_map_prot_check(file, prot,
                                   (flags & MAP_TYPE) == MAP_SHARED);
 }
 
 static int selinux_file_mprotect(struct vm_area_struct *vma,
-                                unsigned long reqprot,
+                                unsigned long reqprot __always_unused,
                                 unsigned long prot)
 {
        const struct cred *cred = current_cred();
        u32 sid = cred_sid(cred);
 
-       if (selinux_state.checkreqprot)
-               prot = reqprot;
-
        if (default_noexec &&
            (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
                int rc = 0;
-               if (vma->vm_start >= vma->vm_mm->start_brk &&
-                   vma->vm_end <= vma->vm_mm->brk) {
-                       rc = avc_has_perm(&selinux_state,
-                                         sid, sid, SECCLASS_PROCESS,
+               if (vma_is_initial_heap(vma)) {
+                       rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
                                          PROCESS__EXECHEAP, NULL);
-               } else if (!vma->vm_file &&
-                          ((vma->vm_start <= vma->vm_mm->start_stack &&
-                            vma->vm_end >= vma->vm_mm->start_stack) ||
+               } else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
                            vma_is_stack_for_current(vma))) {
-                       rc = avc_has_perm(&selinux_state,
-                                         sid, sid, SECCLASS_PROCESS,
+                       rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
                                          PROCESS__EXECSTACK, NULL);
                } else if (vma->vm_file && vma->anon_vma) {
                        /*
@@ -3817,7 +3934,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
                                       struct fown_struct *fown, int signum)
 {
        struct file *file;
-       u32 sid = task_sid(tsk);
+       u32 sid = task_sid_obj(tsk);
        u32 perm;
        struct file_security_struct *fsec;
 
@@ -3831,8 +3948,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
        else
                perm = signal_to_av(signum);
 
-       return avc_has_perm(&selinux_state,
-                           fsec->fown_sid, sid,
+       return avc_has_perm(fsec->fown_sid, sid,
                            SECCLASS_PROCESS, perm, NULL);
 }
 
@@ -3858,7 +3974,7 @@ static int selinux_file_open(struct file *file)
         * struct as its SID.
         */
        fsec->isid = isec->sid;
-       fsec->pseqno = avc_policy_seqno(&selinux_state);
+       fsec->pseqno = avc_policy_seqno();
        /*
         * Since the inode label or policy seqno may have changed
         * between the selinux_inode_permission check and the saving
@@ -3877,8 +3993,7 @@ static int selinux_task_alloc(struct task_struct *task,
 {
        u32 sid = current_sid();
 
-       return avc_has_perm(&selinux_state,
-                           sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
+       return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
 }
 
 /*
@@ -3920,8 +4035,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
        u32 sid = current_sid();
        int ret;
 
-       ret = avc_has_perm(&selinux_state,
-                          sid, secid,
+       ret = avc_has_perm(sid, secid,
                           SECCLASS_KERNEL_SERVICE,
                           KERNEL_SERVICE__USE_AS_OVERRIDE,
                           NULL);
@@ -3945,8 +4059,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
        u32 sid = current_sid();
        int ret;
 
-       ret = avc_has_perm(&selinux_state,
-                          sid, isec->sid,
+       ret = avc_has_perm(sid, isec->sid,
                           SECCLASS_KERNEL_SERVICE,
                           KERNEL_SERVICE__CREATE_FILES_AS,
                           NULL);
@@ -3963,8 +4076,7 @@ static int selinux_kernel_module_request(char *kmod_name)
        ad.type = LSM_AUDIT_DATA_KMOD;
        ad.u.kmod_name = kmod_name;
 
-       return avc_has_perm(&selinux_state,
-                           current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
+       return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
                            SYSTEM__MODULE_REQUEST, &ad);
 }
 
@@ -3978,8 +4090,7 @@ static int selinux_kernel_module_from_file(struct file *file)
 
        /* init_module */
        if (file == NULL)
-               return avc_has_perm(&selinux_state,
-                                   sid, sid, SECCLASS_SYSTEM,
+               return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
                                        SYSTEM__MODULE_LOAD, NULL);
 
        /* finit_module */
@@ -3989,26 +4100,25 @@ static int selinux_kernel_module_from_file(struct file *file)
 
        fsec = selinux_file(file);
        if (sid != fsec->sid) {
-               rc = avc_has_perm(&selinux_state,
-                                 sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
+               rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
                if (rc)
                        return rc;
        }
 
        isec = inode_security(file_inode(file));
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, SECCLASS_SYSTEM,
+       return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
                                SYSTEM__MODULE_LOAD, &ad);
 }
 
 static int selinux_kernel_read_file(struct file *file,
-                                   enum kernel_read_file_id id)
+                                   enum kernel_read_file_id id,
+                                   bool contents)
 {
        int rc = 0;
 
        switch (id) {
        case READING_MODULE:
-               rc = selinux_kernel_module_from_file(file);
+               rc = selinux_kernel_module_from_file(contents ? file : NULL);
                break;
        default:
                break;
@@ -4017,13 +4127,14 @@ static int selinux_kernel_read_file(struct file *file,
        return rc;
 }
 
-static int selinux_kernel_load_data(enum kernel_load_data_id id)
+static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
 {
        int rc = 0;
 
        switch (id) {
        case LOADING_MODULE:
                rc = selinux_kernel_module_from_file(NULL);
+               break;
        default:
                break;
        }
@@ -4033,48 +4144,47 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id)
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__SETPGID, NULL);
 }
 
 static int selinux_task_getpgid(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__GETPGID, NULL);
 }
 
 static int selinux_task_getsid(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__GETSESSION, NULL);
 }
 
-static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
+static void selinux_current_getsecid_subj(u32 *secid)
 {
-       *secid = task_sid(p);
+       *secid = current_sid();
+}
+
+static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
+{
+       *secid = task_sid_obj(p);
 }
 
 static int selinux_task_setnice(struct task_struct *p, int nice)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_getioprio(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__GETSCHED, NULL);
 }
 
@@ -4089,8 +4199,7 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
                av |= PROCESS__SETRLIMIT;
        if (flags & LSM_PRLIMIT_READ)
                av |= PROCESS__GETRLIMIT;
-       return avc_has_perm(&selinux_state,
-                           cred_sid(cred), cred_sid(tcred),
+       return avc_has_perm(cred_sid(cred), cred_sid(tcred),
                            SECCLASS_PROCESS, av, NULL);
 }
 
@@ -4104,8 +4213,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
           later be used as a safe reset point for the soft limit
           upon context transitions.  See selinux_bprm_committing_creds. */
        if (old_rlim->rlim_max != new_rlim->rlim_max)
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), task_sid(p),
+               return avc_has_perm(current_sid(), task_sid_obj(p),
                                    SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
 
        return 0;
@@ -4113,22 +4221,19 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
 
 static int selinux_task_setscheduler(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_getscheduler(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__GETSCHED, NULL);
 }
 
 static int selinux_task_movememory(struct task_struct *p)
 {
-       return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid(p), SECCLASS_PROCESS,
+       return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
                            PROCESS__SETSCHED, NULL);
 }
 
@@ -4146,15 +4251,14 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
                secid = current_sid();
        else
                secid = cred_sid(cred);
-       return avc_has_perm(&selinux_state,
-                           secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
+       return avc_has_perm(secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
 }
 
 static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
 {
        struct inode_security_struct *isec = selinux_inode(inode);
-       u32 sid = task_sid(p);
+       u32 sid = task_sid_obj(p);
 
        spin_lock(&isec->lock);
        isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -4163,6 +4267,14 @@ static void selinux_task_to_inode(struct task_struct *p,
        spin_unlock(&isec->lock);
 }
 
+static int selinux_userns_create(const struct cred *cred)
+{
+       u32 sid = current_sid();
+
+       return avc_has_perm(sid, sid, SECCLASS_USER_NAMESPACE,
+                       USER_NAMESPACE__CREATE, NULL);
+}
+
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                        struct common_audit_data *ad, u8 *proto)
@@ -4418,7 +4530,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
        if (unlikely(err))
                return -EACCES;
 
-       err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
+       err = security_net_peersid_resolve(nlbl_sid,
                                           nlbl_type, xfrm_sid, sid);
        if (unlikely(err)) {
                pr_warn(
@@ -4438,7 +4550,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
  *
  * If @skb_sid is valid then the user:role:type information from @sk_sid is
  * combined with the MLS information from @skb_sid in order to create
- * @conn_sid.  If @skb_sid is not valid then then @conn_sid is simply a copy
+ * @conn_sid.  If @skb_sid is not valid then @conn_sid is simply a copy
  * of @sk_sid.  Returns zero on success, negative values on failure.
  *
  */
@@ -4447,7 +4559,7 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
        int err = 0;
 
        if (skb_sid != SECSID_NULL)
-               err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
+               err = security_sid_mls_copy(sk_sid, skb_sid,
                                            conn_sid);
        else
                *conn_sid = sk_sid;
@@ -4465,7 +4577,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
                return 0;
        }
 
-       return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
+       return security_transition_sid(tsec->sid, tsec->sid,
                                       secclass, NULL, socksid);
 }
 
@@ -4473,17 +4585,29 @@ static int sock_has_perm(struct sock *sk, u32 perms)
 {
        struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
 
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->sk = sk;
+       /*
+        * Before POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, sockets that
+        * inherited the kernel context from early boot used to be skipped
+        * here, so preserve that behavior unless the capability is set.
+        *
+        * By setting the capability the policy signals that it is ready
+        * for this quirk to be fixed. Note that sockets created by a kernel
+        * thread or a usermode helper executed without a transition will
+        * still be skipped in this check regardless of the policycap
+        * setting.
+        */
+       if (!selinux_policycap_userspace_initial_context() &&
+           sksec->sid == SECINITSID_INIT)
+               return 0;
+
+       ad_net_init_from_sk(&ad, &net, sk);
 
-       return avc_has_perm(&selinux_state,
-                           current_sid(), sksec->sid, sksec->sclass, perms,
+       return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
                            &ad);
 }
 
@@ -4503,8 +4627,7 @@ static int selinux_socket_create(int family, int type,
        if (rc)
                return rc;
 
-       return avc_has_perm(&selinux_state,
-                           tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
+       return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
 }
 
 static int selinux_socket_post_create(struct socket *sock, int family,
@@ -4596,6 +4719,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                return -EINVAL;
                        addr4 = (struct sockaddr_in *)address;
                        if (family_sa == AF_UNSPEC) {
+                               if (family == PF_INET6) {
+                                       /* Length check from inet6_bind_sk() */
+                                       if (addrlen < SIN6_LEN_RFC2133)
+                                               return -EINVAL;
+                                       /* Family check from __inet6_bind() */
+                                       goto err_af;
+                               }
                                /* see __inet_bind(), we only want to allow
                                 * AF_UNSPEC if the address is INADDR_ANY
                                 */
@@ -4633,8 +4763,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                                      snum, &sid);
                                if (err)
                                        goto out;
-                               err = avc_has_perm(&selinux_state,
-                                                  sksec->sid, sid,
+                               err = avc_has_perm(sksec->sid, sid,
                                                   sksec->sclass,
                                                   SOCKET__NAME_BIND, &ad);
                                if (err)
@@ -4673,8 +4802,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                else
                        ad.u.net->v6info.saddr = addr6->sin6_addr;
 
-               err = avc_has_perm(&selinux_state,
-                                  sksec->sid, sid,
+               err = avc_has_perm(sksec->sid, sid,
                                   sksec->sclass, node_perm, &ad);
                if (err)
                        goto out;
@@ -4772,8 +4900,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
                ad.u.net = &net;
                ad.u.net->dport = htons(snum);
                ad.u.net->family = address->sa_family;
-               err = avc_has_perm(&selinux_state,
-                                  sksec->sid, sid, sksec->sclass, perm, &ad);
+               err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
                if (err)
                        return err;
        }
@@ -4878,15 +5005,12 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
        struct sk_security_struct *sksec_other = other->sk_security;
        struct sk_security_struct *sksec_new = newsk->sk_security;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
        int err;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->sk = other;
+       ad_net_init_from_sk(&ad, &net, other);
 
-       err = avc_has_perm(&selinux_state,
-                          sksec_sock->sid, sksec_other->sid,
+       err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
                           sksec_other->sclass,
                           UNIX_STREAM_SOCKET__CONNECTTO, &ad);
        if (err)
@@ -4894,7 +5018,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
 
        /* server child socket */
        sksec_new->peer_sid = sksec_sock->sid;
-       err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
+       err = security_sid_mls_copy(sksec_other->sid,
                                    sksec_sock->sid, &sksec_new->sid);
        if (err)
                return err;
@@ -4911,14 +5035,11 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        struct sk_security_struct *ssec = sock->sk->sk_security;
        struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->sk = other->sk;
+       ad_net_init_from_sk(&ad, &net, other->sk);
 
-       return avc_has_perm(&selinux_state,
-                           ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+       return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
                            &ad);
 }
 
@@ -4933,8 +5054,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
        err = sel_netif_sid(ns, ifindex, &if_sid);
        if (err)
                return err;
-       err = avc_has_perm(&selinux_state,
-                          peer_sid, if_sid,
+       err = avc_has_perm(peer_sid, if_sid,
                           SECCLASS_NETIF, NETIF__INGRESS, ad);
        if (err)
                return err;
@@ -4942,8 +5062,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
        err = sel_netnode_sid(addrp, family, &node_sid);
        if (err)
                return err;
-       return avc_has_perm(&selinux_state,
-                           peer_sid, node_sid,
+       return avc_has_perm(peer_sid, node_sid,
                            SECCLASS_NODE, NODE__RECVFROM, ad);
 }
 
@@ -4954,20 +5073,16 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        struct sk_security_struct *sksec = sk->sk_security;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
        char *addrp;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->netif = skb->skb_iif;
-       ad.u.net->family = family;
+       ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
                return err;
 
        if (selinux_secmark_enabled()) {
-               err = avc_has_perm(&selinux_state,
-                                  sk_sid, skb->secmark, SECCLASS_PACKET,
+               err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
                if (err)
                        return err;
@@ -4983,15 +5098,13 @@ 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;
+       int err, peerlbl_active, secmark_active;
        struct sk_security_struct *sksec = sk->sk_security;
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
        char *addrp;
-       u8 secmark_active;
-       u8 peerlbl_active;
 
        if (family != PF_INET && family != PF_INET6)
                return 0;
@@ -5012,10 +5125,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!secmark_active && !peerlbl_active)
                return 0;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->netif = skb->skb_iif;
-       ad.u.net->family = family;
+       ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
                return err;
@@ -5032,8 +5142,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        selinux_netlbl_err(skb, family, err, 0);
                        return err;
                }
-               err = avc_has_perm(&selinux_state,
-                                  sk_sid, peer_sid, SECCLASS_PEER,
+               err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
                                   PEER__RECV, &ad);
                if (err) {
                        selinux_netlbl_err(skb, family, err, 0);
@@ -5042,8 +5151,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
 
        if (secmark_active) {
-               err = avc_has_perm(&selinux_state,
-                                  sk_sid, skb->secmark, SECCLASS_PACKET,
+               err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
                if (err)
                        return err;
@@ -5052,11 +5160,12 @@ 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,
+                                           sockptr_t optval, sockptr_t optlen,
+                                           unsigned int len)
 {
        int err = 0;
-       char *scontext;
+       char *scontext = NULL;
        u32 scontext_len;
        struct sk_security_struct *sksec = sock->sk->sk_security;
        u32 peer_sid = SECSID_NULL;
@@ -5068,31 +5177,29 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
        if (peer_sid == SECSID_NULL)
                return -ENOPROTOOPT;
 
-       err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
+       err = security_sid_to_context(peer_sid, &scontext,
                                      &scontext_len);
        if (err)
                return err;
-
        if (scontext_len > len) {
                err = -ERANGE;
                goto out_len;
        }
 
-       if (copy_to_user(optval, scontext, scontext_len))
+       if (copy_to_sockptr(optval, scontext, scontext_len))
                err = -EFAULT;
-
 out_len:
-       if (put_user(scontext_len, optlen))
+       if (copy_to_sockptr(optlen, &scontext_len, sizeof(scontext_len)))
                err = -EFAULT;
        kfree(scontext);
        return err;
 }
 
-static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+static int selinux_socket_getpeersec_dgram(struct socket *sock,
+                                          struct sk_buff *skb, u32 *secid)
 {
        u32 peer_secid = SECSID_NULL;
        u16 family;
-       struct inode_security_struct *isec;
 
        if (skb && skb->protocol == htons(ETH_P_IP))
                family = PF_INET;
@@ -5100,19 +5207,21 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
                family = PF_INET6;
        else if (sock)
                family = sock->sk->sk_family;
-       else
-               goto out;
+       else {
+               *secid = SECSID_NULL;
+               return -EINVAL;
+       }
 
        if (sock && family == PF_UNIX) {
+               struct inode_security_struct *isec;
                isec = inode_security_novalidate(SOCK_INODE(sock));
                peer_secid = isec->sid;
        } else if (skb)
                selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
-out:
        *secid = peer_secid;
        if (peer_secid == SECSID_NULL)
-               return -EINVAL;
+               return -ENOPROTOOPT;
        return 0;
 }
 
@@ -5154,12 +5263,12 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
        selinux_netlbl_sk_security_reset(newsksec);
 }
 
-static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
+static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
 {
        if (!sk)
                *secid = SECINITSID_ANY_SOCKET;
        else {
-               struct sk_security_struct *sksec = sk->sk_security;
+               const struct sk_security_struct *sksec = sk->sk_security;
 
                *secid = sksec->sid;
        }
@@ -5177,37 +5286,38 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
        sksec->sclass = isec->sclass;
 }
 
-/* Called whenever SCTP receives an INIT chunk. This happens when an incoming
- * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
- * already present).
+/*
+ * Determines peer_secid for the asoc and updates socket's peer label
+ * if it's the first association on the socket.
  */
-static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
-                                     struct sk_buff *skb)
+static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+                                         struct sk_buff *skb)
 {
-       struct sk_security_struct *sksec = ep->base.sk->sk_security;
+       struct sock *sk = asoc->base.sk;
+       u16 family = sk->sk_family;
+       struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
-       u8 peerlbl_active;
-       u32 peer_sid = SECINITSID_UNLABELED;
-       u32 conn_sid;
-       int err = 0;
+       struct lsm_network_audit net;
+       int err;
 
-       if (!selinux_policycap_extsockclass())
-               return 0;
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
 
-       peerlbl_active = selinux_peerlbl_enabled();
+       if (selinux_peerlbl_enabled()) {
+               asoc->peer_secid = SECSID_NULL;
 
-       if (peerlbl_active) {
                /* This will return peer_sid = SECSID_NULL if there are
                 * no peer labels, see security_net_peersid_resolve().
                 */
-               err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family,
-                                             &peer_sid);
+               err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
                if (err)
                        return err;
 
-               if (peer_sid == SECSID_NULL)
-                       peer_sid = SECINITSID_UNLABELED;
+               if (asoc->peer_secid == SECSID_NULL)
+                       asoc->peer_secid = SECINITSID_UNLABELED;
+       } else {
+               asoc->peer_secid = SECINITSID_UNLABELED;
        }
 
        if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
@@ -5218,36 +5328,73 @@ static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
                 * then it is approved by policy and used as the primary
                 * peer SID for getpeercon(3).
                 */
-               sksec->peer_sid = peer_sid;
-       } else if  (sksec->peer_sid != peer_sid) {
+               sksec->peer_sid = asoc->peer_secid;
+       } else if (sksec->peer_sid != asoc->peer_secid) {
                /* Other association peer SIDs are checked to enforce
                 * consistency among the peer SIDs.
                 */
-               ad.type = LSM_AUDIT_DATA_NET;
-               ad.u.net = &net;
-               ad.u.net->sk = ep->base.sk;
-               err = avc_has_perm(&selinux_state,
-                                  sksec->peer_sid, peer_sid, sksec->sclass,
-                                  SCTP_SOCKET__ASSOCIATION, &ad);
+               ad_net_init_from_sk(&ad, &net, asoc->base.sk);
+               err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
+                                  sksec->sclass, SCTP_SOCKET__ASSOCIATION,
+                                  &ad);
                if (err)
                        return err;
        }
+       return 0;
+}
+
+/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This
+ * happens on an incoming connect(2), sctp_connectx(3) or
+ * sctp_sendmsg(3) (with no association already present).
+ */
+static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+                                     struct sk_buff *skb)
+{
+       struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+       u32 conn_sid;
+       int err;
+
+       if (!selinux_policycap_extsockclass())
+               return 0;
+
+       err = selinux_sctp_process_new_assoc(asoc, skb);
+       if (err)
+               return err;
 
        /* Compute the MLS component for the connection and store
-        * the information in ep. This will be used by SCTP TCP type
+        * the information in asoc. This will be used by SCTP TCP type
         * sockets and peeled off connections as they cause a new
         * socket to be generated. selinux_sctp_sk_clone() will then
         * plug this into the new socket.
         */
-       err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
+       err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
        if (err)
                return err;
 
-       ep->secid = conn_sid;
-       ep->peer_secid = peer_sid;
+       asoc->secid = conn_sid;
 
        /* Set any NetLabel labels including CIPSO/CALIPSO options. */
-       return selinux_netlbl_sctp_assoc_request(ep, skb);
+       return selinux_netlbl_sctp_assoc_request(asoc, skb);
+}
+
+/* Called when SCTP receives a COOKIE ACK chunk as the final
+ * response to an association request (initited by us).
+ */
+static int selinux_sctp_assoc_established(struct sctp_association *asoc,
+                                         struct sk_buff *skb)
+{
+       struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+
+       if (!selinux_policycap_extsockclass())
+               return 0;
+
+       /* Inherit secid from the parent socket - this will be picked up
+        * by selinux_sctp_sk_clone() if the association gets peeled off
+        * into a new socket.
+        */
+       asoc->secid = sksec->sid;
+
+       return selinux_sctp_process_new_assoc(asoc, skb);
 }
 
 /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
@@ -5308,7 +5455,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
 
                        /* As selinux_sctp_bind_connect() is called by the
                         * SCTP protocol layer, the socket is already locked,
-                        * therefore selinux_netlbl_socket_connect_locked() is
+                        * therefore selinux_netlbl_socket_connect_locked()
                         * is called here. The situations handled are:
                         * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
                         * whenever a new IP address is added or when a new
@@ -5332,7 +5479,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
 }
 
 /* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
-static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
+static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
                                  struct sock *newsk)
 {
        struct sk_security_struct *sksec = sk->sk_security;
@@ -5344,13 +5491,28 @@ static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
        if (!selinux_policycap_extsockclass())
                return selinux_sk_clone_security(sk, newsk);
 
-       newsksec->sid = ep->secid;
-       newsksec->peer_sid = ep->peer_secid;
+       newsksec->sid = asoc->secid;
+       newsksec->peer_sid = asoc->peer_secid;
        newsksec->sclass = sksec->sclass;
        selinux_netlbl_sctp_sk_clone(sk, newsk);
 }
 
-static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+       struct sk_security_struct *ssksec = ssk->sk_security;
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       ssksec->sclass = sksec->sclass;
+       ssksec->sid = sksec->sid;
+
+       /* replace the existing subflow label deleting the existing one
+        * and re-recreating a new label using the updated context
+        */
+       selinux_netlbl_sk_security_free(ssksec);
+       return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
+}
+
+static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
                                     struct request_sock *req)
 {
        struct sk_security_struct *sksec = sk->sk_security;
@@ -5402,14 +5564,13 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 
 static int selinux_secmark_relabel_packet(u32 sid)
 {
-       const struct task_security_struct *__tsec;
+       const struct task_security_struct *tsec;
        u32 tsid;
 
-       __tsec = selinux_cred(current_cred());
-       tsid = __tsec->sid;
+       tsec = selinux_cred(current_cred());
+       tsid = tsec->sid;
 
-       return avc_has_perm(&selinux_state,
-                           tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
+       return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
                            NULL);
 }
 
@@ -5424,9 +5585,9 @@ static void selinux_secmark_refcount_dec(void)
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
-                                     struct flowi *fl)
+                                     struct flowi_common *flic)
 {
-       fl->flowi_secid = req->secid;
+       flic->flowic_secid = req->secid;
 }
 
 static int selinux_tun_dev_alloc_security(void **security)
@@ -5458,8 +5619,7 @@ static int selinux_tun_dev_create(void)
         * connections unlike traditional sockets - check the TUN driver to
         * get a better understanding of why this socket is special */
 
-       return avc_has_perm(&selinux_state,
-                           sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+       return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
                            NULL);
 }
 
@@ -5467,8 +5627,7 @@ static int selinux_tun_dev_attach_queue(void *security)
 {
        struct tun_security_struct *tunsec = security;
 
-       return avc_has_perm(&selinux_state,
-                           current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
+       return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
                            TUN_SOCKET__ATTACH_QUEUE, NULL);
 }
 
@@ -5496,13 +5655,11 @@ static int selinux_tun_dev_open(void *security)
        u32 sid = current_sid();
        int err;
 
-       err = avc_has_perm(&selinux_state,
-                          sid, tunsec->sid, SECCLASS_TUN_SOCKET,
+       err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
                           TUN_SOCKET__RELABELFROM, NULL);
        if (err)
                return err;
-       err = avc_has_perm(&selinux_state,
-                          sid, sid, SECCLASS_TUN_SOCKET,
+       err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
                           TUN_SOCKET__RELABELTO, NULL);
        if (err)
                return err;
@@ -5513,40 +5670,38 @@ static int selinux_tun_dev_open(void *security)
 
 #ifdef CONFIG_NETFILTER
 
-static unsigned int selinux_ip_forward(struct sk_buff *skb,
-                                      const struct net_device *indev,
-                                      u16 family)
+static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
+                                      const struct nf_hook_state *state)
 {
-       int err;
+       int ifindex;
+       u16 family;
        char *addrp;
        u32 peer_sid;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
-       u8 secmark_active;
-       u8 netlbl_active;
-       u8 peerlbl_active;
+       struct lsm_network_audit net;
+       int secmark_active, peerlbl_active;
 
        if (!selinux_policycap_netpeer())
                return NF_ACCEPT;
 
        secmark_active = selinux_secmark_enabled();
-       netlbl_active = netlbl_enabled();
        peerlbl_active = selinux_peerlbl_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
+       family = state->pf;
        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
                return NF_DROP;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->netif = indev->ifindex;
-       ad.u.net->family = family;
+       ifindex = state->in->ifindex;
+       ad_net_init_from_iif(&ad, &net, ifindex, family);
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
 
        if (peerlbl_active) {
-               err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
+               int err;
+
+               err = selinux_inet_sys_rcv_skb(state->net, ifindex,
                                               addrp, family, peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, family, err, 1);
@@ -5555,12 +5710,11 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
        }
 
        if (secmark_active)
-               if (avc_has_perm(&selinux_state,
-                                peer_sid, skb->secmark,
+               if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
                        return NF_DROP;
 
-       if (netlbl_active)
+       if (netlbl_enabled())
                /* we do this in the FORWARD path and not the POST_ROUTING
                 * path because we want to make sure we apply the necessary
                 * labeling before IPsec is applied so we can leverage AH
@@ -5571,24 +5725,8 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
-static unsigned int selinux_ipv4_forward(void *priv,
-                                        struct sk_buff *skb,
-                                        const struct nf_hook_state *state)
-{
-       return selinux_ip_forward(skb, state->in, PF_INET);
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static unsigned int selinux_ipv6_forward(void *priv,
-                                        struct sk_buff *skb,
-                                        const struct nf_hook_state *state)
-{
-       return selinux_ip_forward(skb, state->in, PF_INET6);
-}
-#endif /* IPV6 */
-
-static unsigned int selinux_ip_output(struct sk_buff *skb,
-                                     u16 family)
+static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
+                                     const struct nf_hook_state *state)
 {
        struct sock *sk;
        u32 sid;
@@ -5623,53 +5761,33 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
                sid = sksec->sid;
        } else
                sid = SECINITSID_KERNEL;
-       if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+       if (selinux_netlbl_skbuff_setsid(skb, state->pf, sid) != 0)
                return NF_DROP;
 
        return NF_ACCEPT;
 }
 
-static unsigned int selinux_ipv4_output(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state)
-{
-       return selinux_ip_output(skb, PF_INET);
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static unsigned int selinux_ipv6_output(void *priv,
-                                       struct sk_buff *skb,
-                                       const struct nf_hook_state *state)
-{
-       return selinux_ip_output(skb, PF_INET6);
-}
-#endif /* IPV6 */
 
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
-                                               int ifindex,
-                                               u16 family)
+                                       const struct nf_hook_state *state)
 {
-       struct sock *sk = skb_to_full_sk(skb);
+       struct sock *sk;
        struct sk_security_struct *sksec;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
-       char *addrp;
-       u8 proto;
+       struct lsm_network_audit net;
+       u8 proto = 0;
 
+       sk = skb_to_full_sk(skb);
        if (sk == NULL)
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->netif = ifindex;
-       ad.u.net->family = family;
-       if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
+       ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
+       if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
                return NF_DROP;
 
        if (selinux_secmark_enabled())
-               if (avc_has_perm(&selinux_state,
-                                sksec->sid, skb->secmark,
+               if (avc_has_perm(sksec->sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
 
@@ -5679,26 +5797,26 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
-static unsigned int selinux_ip_postroute(struct sk_buff *skb,
-                                        const struct net_device *outdev,
-                                        u16 family)
+static unsigned int selinux_ip_postroute(void *priv,
+                                        struct sk_buff *skb,
+                                        const struct nf_hook_state *state)
 {
+       u16 family;
        u32 secmark_perm;
        u32 peer_sid;
-       int ifindex = outdev->ifindex;
+       int ifindex;
        struct sock *sk;
        struct common_audit_data ad;
-       struct lsm_network_audit net = {0,};
+       struct lsm_network_audit net;
        char *addrp;
-       u8 secmark_active;
-       u8 peerlbl_active;
+       int secmark_active, peerlbl_active;
 
        /* If any sort of compatibility mode is enabled then handoff processing
         * to the selinux_ip_postroute_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
        if (!selinux_policycap_netpeer())
-               return selinux_ip_postroute_compat(skb, ifindex, family);
+               return selinux_ip_postroute_compat(skb, state);
 
        secmark_active = selinux_secmark_enabled();
        peerlbl_active = selinux_peerlbl_enabled();
@@ -5724,6 +5842,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
                return NF_ACCEPT;
 #endif
 
+       family = state->pf;
        if (sk == NULL) {
                /* Without an associated socket the packet is either coming
                 * from the kernel or it is being forwarded; check the packet
@@ -5784,16 +5903,13 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
                secmark_perm = PACKET__SEND;
        }
 
-       ad.type = LSM_AUDIT_DATA_NET;
-       ad.u.net = &net;
-       ad.u.net->netif = ifindex;
-       ad.u.net->family = family;
+       ifindex = state->out->ifindex;
+       ad_net_init_from_iif(&ad, &net, ifindex, family);
        if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
                return NF_DROP;
 
        if (secmark_active)
-               if (avc_has_perm(&selinux_state,
-                                peer_sid, skb->secmark,
+               if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, secmark_perm, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
 
@@ -5801,40 +5917,21 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
                u32 if_sid;
                u32 node_sid;
 
-               if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
+               if (sel_netif_sid(state->net, ifindex, &if_sid))
                        return NF_DROP;
-               if (avc_has_perm(&selinux_state,
-                                peer_sid, if_sid,
+               if (avc_has_perm(peer_sid, if_sid,
                                 SECCLASS_NETIF, NETIF__EGRESS, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
 
                if (sel_netnode_sid(addrp, family, &node_sid))
                        return NF_DROP;
-               if (avc_has_perm(&selinux_state,
-                                peer_sid, node_sid,
+               if (avc_has_perm(peer_sid, node_sid,
                                 SECCLASS_NODE, NODE__SENDTO, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
        }
 
        return NF_ACCEPT;
 }
-
-static unsigned int selinux_ipv4_postroute(void *priv,
-                                          struct sk_buff *skb,
-                                          const struct nf_hook_state *state)
-{
-       return selinux_ip_postroute(skb, state->out, PF_INET);
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-static unsigned int selinux_ipv6_postroute(void *priv,
-                                          struct sk_buff *skb,
-                                          const struct nf_hook_state *state)
-{
-       return selinux_ip_postroute(skb, state->out, PF_INET6);
-}
-#endif /* IPV6 */
-
 #endif /* CONFIG_NETFILTER */
 
 static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
@@ -5873,8 +5970,8 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
                                sk->sk_protocol, nlh->nlmsg_type,
                                secclass_map[sclass - 1].name,
                                task_pid_nr(current), current->comm);
-                       if (enforcing_enabled(&selinux_state) &&
-                           !security_get_allow_unknown(&selinux_state))
+                       if (enforcing_enabled() &&
+                           !security_get_allow_unknown())
                                return rc;
                        rc = 0;
                } else if (rc == -ENOENT) {
@@ -5913,8 +6010,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = ipc_perms->key;
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, isec->sclass, perms, &ad);
+       return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -5933,7 +6029,6 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
        struct ipc_security_struct *isec;
        struct common_audit_data ad;
        u32 sid = current_sid();
-       int rc;
 
        isec = selinux_ipc(msq);
        ipc_init_security(isec, SECCLASS_MSGQ);
@@ -5941,10 +6036,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, SECCLASS_MSGQ,
-                         MSGQ__CREATE, &ad);
-       return rc;
+       return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+                           MSGQ__CREATE, &ad);
 }
 
 static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -5958,22 +6051,19 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, SECCLASS_MSGQ,
+       return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                            MSGQ__ASSOCIATE, &ad);
 }
 
 static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
 {
-       int err;
-       int perms;
+       u32 perms;
 
        switch (cmd) {
        case IPC_INFO:
        case MSG_INFO:
                /* No specific object, just general system-wide information. */
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), SECINITSID_KERNEL,
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                                    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case IPC_STAT:
        case MSG_STAT:
@@ -5990,8 +6080,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
                return 0;
        }
 
-       err = ipc_has_perm(msq, perms);
-       return err;
+       return ipc_has_perm(msq, perms);
 }
 
 static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
@@ -6013,7 +6102,7 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
                 * Compute new sid based on current process and
                 * message queue this message will be stored in
                 */
-               rc = security_transition_sid(&selinux_state, sid, isec->sid,
+               rc = security_transition_sid(sid, isec->sid,
                                             SECCLASS_MSG, NULL, &msec->sid);
                if (rc)
                        return rc;
@@ -6023,18 +6112,15 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
        ad.u.ipc_id = msq->key;
 
        /* Can this process write to the queue? */
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, SECCLASS_MSGQ,
+       rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__WRITE, &ad);
        if (!rc)
                /* Can this process send the message */
-               rc = avc_has_perm(&selinux_state,
-                                 sid, msec->sid, SECCLASS_MSG,
+               rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
                                  MSG__SEND, &ad);
        if (!rc)
                /* Can the message be put in the queue? */
-               rc = avc_has_perm(&selinux_state,
-                                 msec->sid, isec->sid, SECCLASS_MSGQ,
+               rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
                                  MSGQ__ENQUEUE, &ad);
 
        return rc;
@@ -6047,7 +6133,7 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
        struct common_audit_data ad;
-       u32 sid = task_sid(target);
+       u32 sid = task_sid_obj(target);
        int rc;
 
        isec = selinux_ipc(msq);
@@ -6056,12 +6142,10 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid,
+       rc = avc_has_perm(sid, isec->sid,
                          SECCLASS_MSGQ, MSGQ__READ, &ad);
        if (!rc)
-               rc = avc_has_perm(&selinux_state,
-                                 sid, msec->sid,
+               rc = avc_has_perm(sid, msec->sid,
                                  SECCLASS_MSG, MSG__RECEIVE, &ad);
        return rc;
 }
@@ -6072,7 +6156,6 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
        struct ipc_security_struct *isec;
        struct common_audit_data ad;
        u32 sid = current_sid();
-       int rc;
 
        isec = selinux_ipc(shp);
        ipc_init_security(isec, SECCLASS_SHM);
@@ -6080,10 +6163,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, SECCLASS_SHM,
-                         SHM__CREATE, &ad);
-       return rc;
+       return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
+                           SHM__CREATE, &ad);
 }
 
 static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -6097,23 +6178,20 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, SECCLASS_SHM,
+       return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
                            SHM__ASSOCIATE, &ad);
 }
 
 /* Note, at this point, shp is locked down */
 static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
 {
-       int perms;
-       int err;
+       u32 perms;
 
        switch (cmd) {
        case IPC_INFO:
        case SHM_INFO:
                /* No specific object, just general system-wide information. */
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), SECINITSID_KERNEL,
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                                    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case IPC_STAT:
        case SHM_STAT:
@@ -6134,8 +6212,7 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
                return 0;
        }
 
-       err = ipc_has_perm(shp, perms);
-       return err;
+       return ipc_has_perm(shp, perms);
 }
 
 static int selinux_shm_shmat(struct kern_ipc_perm *shp,
@@ -6157,7 +6234,6 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
        struct ipc_security_struct *isec;
        struct common_audit_data ad;
        u32 sid = current_sid();
-       int rc;
 
        isec = selinux_ipc(sma);
        ipc_init_security(isec, SECCLASS_SEM);
@@ -6165,10 +6241,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
 
-       rc = avc_has_perm(&selinux_state,
-                         sid, isec->sid, SECCLASS_SEM,
-                         SEM__CREATE, &ad);
-       return rc;
+       return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
+                           SEM__CREATE, &ad);
 }
 
 static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -6182,8 +6256,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
 
-       return avc_has_perm(&selinux_state,
-                           sid, isec->sid, SECCLASS_SEM,
+       return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
                            SEM__ASSOCIATE, &ad);
 }
 
@@ -6197,8 +6270,7 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
        case IPC_INFO:
        case SEM_INFO:
                /* No specific object, just general system-wide information. */
-               return avc_has_perm(&selinux_state,
-                                   current_sid(), SECINITSID_KERNEL,
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
                                    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case GETPID:
        case GETNCNT:
@@ -6273,8 +6345,8 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
                inode_doinit_with_dentry(inode, dentry);
 }
 
-static int selinux_getprocattr(struct task_struct *p,
-                              char *name, char **value)
+static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
+                              char **value)
 {
        const struct task_security_struct *__tsec;
        u32 sid;
@@ -6285,27 +6357,33 @@ static int selinux_getprocattr(struct task_struct *p,
        __tsec = selinux_cred(__task_cred(p));
 
        if (current != p) {
-               error = avc_has_perm(&selinux_state,
-                                    current_sid(), __tsec->sid,
+               error = avc_has_perm(current_sid(), __tsec->sid,
                                     SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
                if (error)
                        goto bad;
        }
 
-       if (!strcmp(name, "current"))
+       switch (attr) {
+       case LSM_ATTR_CURRENT:
                sid = __tsec->sid;
-       else if (!strcmp(name, "prev"))
+               break;
+       case LSM_ATTR_PREV:
                sid = __tsec->osid;
-       else if (!strcmp(name, "exec"))
+               break;
+       case LSM_ATTR_EXEC:
                sid = __tsec->exec_sid;
-       else if (!strcmp(name, "fscreate"))
+               break;
+       case LSM_ATTR_FSCREATE:
                sid = __tsec->create_sid;
-       else if (!strcmp(name, "keycreate"))
+               break;
+       case LSM_ATTR_KEYCREATE:
                sid = __tsec->keycreate_sid;
-       else if (!strcmp(name, "sockcreate"))
+               break;
+       case LSM_ATTR_SOCKCREATE:
                sid = __tsec->sockcreate_sid;
-       else {
-               error = -EINVAL;
+               break;
+       default:
+               error = -EOPNOTSUPP;
                goto bad;
        }
        rcu_read_unlock();
@@ -6313,7 +6391,7 @@ static int selinux_getprocattr(struct task_struct *p,
        if (!sid)
                return 0;
 
-       error = security_sid_to_context(&selinux_state, sid, value, &len);
+       error = security_sid_to_context(sid, value, &len);
        if (error)
                return error;
        return len;
@@ -6323,7 +6401,7 @@ bad:
        return error;
 }
 
-static int selinux_setprocattr(const char *name, void *value, size_t size)
+static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
 {
        struct task_security_struct *tsec;
        struct cred *new;
@@ -6334,28 +6412,31 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
        /*
         * Basic control over ability to set these attributes at all.
         */
-       if (!strcmp(name, "exec"))
-               error = avc_has_perm(&selinux_state,
-                                    mysid, mysid, SECCLASS_PROCESS,
+       switch (attr) {
+       case LSM_ATTR_EXEC:
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
                                     PROCESS__SETEXEC, NULL);
-       else if (!strcmp(name, "fscreate"))
-               error = avc_has_perm(&selinux_state,
-                                    mysid, mysid, SECCLASS_PROCESS,
+               break;
+       case LSM_ATTR_FSCREATE:
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
                                     PROCESS__SETFSCREATE, NULL);
-       else if (!strcmp(name, "keycreate"))
-               error = avc_has_perm(&selinux_state,
-                                    mysid, mysid, SECCLASS_PROCESS,
+               break;
+       case LSM_ATTR_KEYCREATE:
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
                                     PROCESS__SETKEYCREATE, NULL);
-       else if (!strcmp(name, "sockcreate"))
-               error = avc_has_perm(&selinux_state,
-                                    mysid, mysid, SECCLASS_PROCESS,
+               break;
+       case LSM_ATTR_SOCKCREATE:
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
                                     PROCESS__SETSOCKCREATE, NULL);
-       else if (!strcmp(name, "current"))
-               error = avc_has_perm(&selinux_state,
-                                    mysid, mysid, SECCLASS_PROCESS,
+               break;
+       case LSM_ATTR_CURRENT:
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
                                     PROCESS__SETCURRENT, NULL);
-       else
-               error = -EINVAL;
+               break;
+       default:
+               error = -EOPNOTSUPP;
+               break;
+       }
        if (error)
                return error;
 
@@ -6365,15 +6446,16 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
                        str[size-1] = 0;
                        size--;
                }
-               error = security_context_to_sid(&selinux_state, value, size,
+               error = security_context_to_sid(value, size,
                                                &sid, GFP_KERNEL);
-               if (error == -EINVAL && !strcmp(name, "fscreate")) {
+               if (error == -EINVAL && attr == LSM_ATTR_FSCREATE) {
                        if (!has_cap_mac_admin(true)) {
                                struct audit_buffer *ab;
                                size_t audit_size;
 
-                               /* We strip a nul only if it is at the end, otherwise the
-                                * context contains a nul and we should audit that */
+                               /* We strip a nul only if it is at the end,
+                                * otherwise the context contains a nul and
+                                * we should audit that */
                                if (str[size - 1] == '\0')
                                        audit_size = size - 1;
                                else
@@ -6381,15 +6463,17 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
                                ab = audit_log_start(audit_context(),
                                                     GFP_ATOMIC,
                                                     AUDIT_SELINUX_ERR);
+                               if (!ab)
+                                       return error;
                                audit_log_format(ab, "op=fscreate invalid_context=");
-                               audit_log_n_untrustedstring(ab, value, audit_size);
+                               audit_log_n_untrustedstring(ab, value,
+                                                           audit_size);
                                audit_log_end(ab);
 
                                return error;
                        }
-                       error = security_context_to_sid_force(
-                                                     &selinux_state,
-                                                     value, size, &sid);
+                       error = security_context_to_sid_force(value, size,
+                                                       &sid);
                }
                if (error)
                        return error;
@@ -6406,37 +6490,33 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
           checks and may_create for the file creation checks. The
           operation will then fail if the context is not permitted. */
        tsec = selinux_cred(new);
-       if (!strcmp(name, "exec")) {
+       if (attr == LSM_ATTR_EXEC) {
                tsec->exec_sid = sid;
-       } else if (!strcmp(name, "fscreate")) {
+       } else if (attr == LSM_ATTR_FSCREATE) {
                tsec->create_sid = sid;
-       } else if (!strcmp(name, "keycreate")) {
+       } else if (attr == LSM_ATTR_KEYCREATE) {
                if (sid) {
-                       error = avc_has_perm(&selinux_state, mysid, sid,
+                       error = avc_has_perm(mysid, sid,
                                             SECCLASS_KEY, KEY__CREATE, NULL);
                        if (error)
                                goto abort_change;
                }
                tsec->keycreate_sid = sid;
-       } else if (!strcmp(name, "sockcreate")) {
+       } else if (attr == LSM_ATTR_SOCKCREATE) {
                tsec->sockcreate_sid = sid;
-       } else if (!strcmp(name, "current")) {
+       } else if (attr == LSM_ATTR_CURRENT) {
                error = -EINVAL;
                if (sid == 0)
                        goto abort_change;
 
-               /* Only allow single threaded processes to change context */
-               error = -EPERM;
                if (!current_is_single_threaded()) {
-                       error = security_bounded_transition(&selinux_state,
-                                                           tsec->sid, sid);
+                       error = security_bounded_transition(tsec->sid, sid);
                        if (error)
                                goto abort_change;
                }
 
                /* Check permissions for the transition. */
-               error = avc_has_perm(&selinux_state,
-                                    tsec->sid, sid, SECCLASS_PROCESS,
+               error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
                                     PROCESS__DYNTRANSITION, NULL);
                if (error)
                        goto abort_change;
@@ -6445,8 +6525,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
                   Otherwise, leave SID unchanged and fail. */
                ptsid = ptrace_parent_sid();
                if (ptsid != 0) {
-                       error = avc_has_perm(&selinux_state,
-                                            ptsid, sid, SECCLASS_PROCESS,
+                       error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
                                             PROCESS__PTRACE, NULL);
                        if (error)
                                goto abort_change;
@@ -6466,6 +6545,69 @@ abort_change:
        return error;
 }
 
+/**
+ * selinux_getselfattr - Get SELinux current task attributes
+ * @attr: the requested attribute
+ * @ctx: buffer to receive the result
+ * @size: buffer size (input), buffer size used (output)
+ * @flags: unused
+ *
+ * Fill the passed user space @ctx with the details of the requested
+ * attribute.
+ *
+ * Returns the number of attributes on success, an error code otherwise.
+ * There will only ever be one attribute.
+ */
+static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
+                              u32 *size, u32 flags)
+{
+       int rc;
+       char *val = NULL;
+       int val_len;
+
+       val_len = selinux_lsm_getattr(attr, current, &val);
+       if (val_len < 0)
+               return val_len;
+       rc = lsm_fill_user_ctx(ctx, size, val, val_len, LSM_ID_SELINUX, 0);
+       kfree(val);
+       return (!rc ? 1 : rc);
+}
+
+static int selinux_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
+                              u32 size, u32 flags)
+{
+       int rc;
+
+       rc = selinux_lsm_setattr(attr, ctx->ctx, ctx->ctx_len);
+       if (rc > 0)
+               return 0;
+       return rc;
+}
+
+static int selinux_getprocattr(struct task_struct *p,
+                              const char *name, char **value)
+{
+       unsigned int attr = lsm_name_to_attr(name);
+       int rc;
+
+       if (attr) {
+               rc = selinux_lsm_getattr(attr, p, value);
+               if (rc != -EOPNOTSUPP)
+                       return rc;
+       }
+
+       return -EINVAL;
+}
+
+static int selinux_setprocattr(const char *name, void *value, size_t size)
+{
+       int attr = lsm_name_to_attr(name);
+
+       if (attr)
+               return selinux_lsm_setattr(attr, value, size);
+       return -EINVAL;
+}
+
 static int selinux_ismaclabel(const char *name)
 {
        return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
@@ -6473,13 +6615,13 @@ static int selinux_ismaclabel(const char *name)
 
 static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
-       return security_sid_to_context(&selinux_state, secid,
+       return security_sid_to_context(secid,
                                       secdata, seclen);
 }
 
 static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       return security_context_to_sid(&selinux_state, secdata, seclen,
+       return security_context_to_sid(secdata, seclen,
                                       secid, GFP_KERNEL);
 }
 
@@ -6513,14 +6655,15 @@ static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen
  */
 static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
 {
-       return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
+       return __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_SELINUX,
+                                    ctx, ctxlen, 0);
 }
 
 static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 {
        int len = 0;
-       len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
-                                               ctx, true);
+       len = selinux_inode_getsecurity(&nop_mnt_idmap, inode,
+                                       XATTR_SELINUX_SUFFIX, ctx, true);
        if (len < 0)
                return len;
        *ctxlen = len;
@@ -6598,8 +6741,7 @@ static int selinux_key_permission(key_ref_t key_ref,
        key = key_ref_to_ptr(key_ref);
        ksec = key->security;
 
-       return avc_has_perm(&selinux_state,
-                           sid, ksec->sid, SECCLASS_KEY, perm, NULL);
+       return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
 }
 
 static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -6609,7 +6751,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
        unsigned len;
        int rc;
 
-       rc = security_sid_to_context(&selinux_state, ksec->sid,
+       rc = security_sid_to_context(ksec->sid,
                                     &context, &len);
        if (!rc)
                rc = len;
@@ -6623,8 +6765,7 @@ static int selinux_watch_key(struct key *key)
        struct key_security_struct *ksec = key->security;
        u32 sid = current_sid();
 
-       return avc_has_perm(&selinux_state,
-                           sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
+       return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
 }
 #endif
 #endif
@@ -6646,8 +6787,7 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
        ibpkey.subnet_prefix = subnet_prefix;
        ibpkey.pkey = pkey_val;
        ad.u.ibpkey = &ibpkey;
-       return avc_has_perm(&selinux_state,
-                           sec->sid, sid,
+       return avc_has_perm(sec->sid, sid,
                            SECCLASS_INFINIBAND_PKEY,
                            INFINIBAND_PKEY__ACCESS, &ad);
 }
@@ -6661,18 +6801,17 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
        struct ib_security_struct *sec = ib_sec;
        struct lsm_ibendport_audit ibendport;
 
-       err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
+       err = security_ib_endport_sid(dev_name, port_num,
                                      &sid);
 
        if (err)
                return err;
 
        ad.type = LSM_AUDIT_DATA_IBENDPORT;
-       strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
+       ibendport.dev_name = dev_name;
        ibendport.port = port_num;
        ad.u.ibendport = &ibendport;
-       return avc_has_perm(&selinux_state,
-                           sec->sid, sid,
+       return avc_has_perm(sec->sid, sid,
                            SECCLASS_INFINIBAND_ENDPORT,
                            INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
 }
@@ -6705,13 +6844,11 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
 
        switch (cmd) {
        case BPF_MAP_CREATE:
-               ret = avc_has_perm(&selinux_state,
-                                  sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+               ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
                                   NULL);
                break;
        case BPF_PROG_LOAD:
-               ret = avc_has_perm(&selinux_state,
-                                  sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+               ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
                                   NULL);
                break;
        default:
@@ -6734,14 +6871,14 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
 }
 
 /* This function will check the file pass through unix socket or binder to see
- * if it is a bpf related object. And apply correspinding checks on the bpf
+ * if it is a bpf related object. And apply corresponding checks on the bpf
  * object based on the type. The bpf maps and programs, not like other files and
  * socket, are using a shared anonymous inode inside the kernel as their inode.
  * So checking that inode cannot identify if the process have privilege to
  * access the bpf object and that's why we have to add this additional check in
  * selinux_file_receive and selinux_binder_transfer_files.
  */
-static int bpf_fd_pass(struct file *file, u32 sid)
+static int bpf_fd_pass(const struct file *file, u32 sid)
 {
        struct bpf_security_struct *bpfsec;
        struct bpf_prog *prog;
@@ -6751,16 +6888,14 @@ static int bpf_fd_pass(struct file *file, u32 sid)
        if (file->f_op == &bpf_map_fops) {
                map = file->private_data;
                bpfsec = map->security;
-               ret = avc_has_perm(&selinux_state,
-                                  sid, bpfsec->sid, SECCLASS_BPF,
+               ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
                                   bpf_map_fmode_to_av(file->f_mode), NULL);
                if (ret)
                        return ret;
        } else if (file->f_op == &bpf_prog_fops) {
                prog = file->private_data;
                bpfsec = prog->aux->security;
-               ret = avc_has_perm(&selinux_state,
-                                  sid, bpfsec->sid, SECCLASS_BPF,
+               ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
                                   BPF__PROG_RUN, NULL);
                if (ret)
                        return ret;
@@ -6774,8 +6909,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
        struct bpf_security_struct *bpfsec;
 
        bpfsec = map->security;
-       return avc_has_perm(&selinux_state,
-                           sid, bpfsec->sid, SECCLASS_BPF,
+       return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
                            bpf_map_fmode_to_av(fmode), NULL);
 }
 
@@ -6785,12 +6919,12 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
        struct bpf_security_struct *bpfsec;
 
        bpfsec = prog->aux->security;
-       return avc_has_perm(&selinux_state,
-                           sid, bpfsec->sid, SECCLASS_BPF,
+       return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
                            BPF__PROG_RUN, NULL);
 }
 
-static int selinux_bpf_map_alloc(struct bpf_map *map)
+static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
+                                 struct bpf_token *token)
 {
        struct bpf_security_struct *bpfsec;
 
@@ -6812,7 +6946,8 @@ static void selinux_bpf_map_free(struct bpf_map *map)
        kfree(bpfsec);
 }
 
-static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
+                                struct bpf_token *token)
 {
        struct bpf_security_struct *bpfsec;
 
@@ -6821,54 +6956,51 @@ static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
                return -ENOMEM;
 
        bpfsec->sid = current_sid();
-       aux->security = bpfsec;
+       prog->aux->security = bpfsec;
 
        return 0;
 }
 
-static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+static void selinux_bpf_prog_free(struct bpf_prog *prog)
 {
-       struct bpf_security_struct *bpfsec = aux->security;
+       struct bpf_security_struct *bpfsec = prog->aux->security;
 
-       aux->security = NULL;
+       prog->aux->security = NULL;
        kfree(bpfsec);
 }
-#endif
 
-static int selinux_lockdown(enum lockdown_reason what)
+static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
+                                   struct path *path)
 {
-       struct common_audit_data ad;
-       u32 sid = current_sid();
-       int invalid_reason = (what <= LOCKDOWN_NONE) ||
-                            (what == LOCKDOWN_INTEGRITY_MAX) ||
-                            (what >= LOCKDOWN_CONFIDENTIALITY_MAX);
-
-       if (WARN(invalid_reason, "Invalid lockdown reason")) {
-               audit_log(audit_context(),
-                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                         "lockdown_reason=invalid");
-               return -EINVAL;
-       }
+       struct bpf_security_struct *bpfsec;
+
+       bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+       if (!bpfsec)
+               return -ENOMEM;
 
-       ad.type = LSM_AUDIT_DATA_LOCKDOWN;
-       ad.u.reason = what;
+       bpfsec->sid = current_sid();
+       token->security = bpfsec;
 
-       if (what <= LOCKDOWN_INTEGRITY_MAX)
-               return avc_has_perm(&selinux_state,
-                                   sid, sid, SECCLASS_LOCKDOWN,
-                                   LOCKDOWN__INTEGRITY, &ad);
-       else
-               return avc_has_perm(&selinux_state,
-                                   sid, sid, SECCLASS_LOCKDOWN,
-                                   LOCKDOWN__CONFIDENTIALITY, &ad);
+       return 0;
+}
+
+static void selinux_bpf_token_free(struct bpf_token *token)
+{
+       struct bpf_security_struct *bpfsec = token->security;
+
+       token->security = NULL;
+       kfree(bpfsec);
 }
+#endif
 
-struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
+struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
        .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),
        .lbs_msg_msg = sizeof(struct msg_security_struct),
+       .lbs_superblock = sizeof(struct superblock_security_struct),
+       .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
 };
 
 #ifdef CONFIG_PERF_EVENTS
@@ -6887,7 +7019,7 @@ static int selinux_perf_event_open(struct perf_event_attr *attr, int type)
        else
                return -EINVAL;
 
-       return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT,
+       return avc_has_perm(sid, sid, SECCLASS_PERF_EVENT,
                            requested, NULL);
 }
 
@@ -6918,7 +7050,7 @@ static int selinux_perf_event_read(struct perf_event *event)
        struct perf_event_security_struct *perfsec = event->security;
        u32 sid = current_sid();
 
-       return avc_has_perm(&selinux_state, sid, perfsec->sid,
+       return avc_has_perm(sid, perfsec->sid,
                            SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
 }
 
@@ -6927,11 +7059,67 @@ static int selinux_perf_event_write(struct perf_event *event)
        struct perf_event_security_struct *perfsec = event->security;
        u32 sid = current_sid();
 
-       return avc_has_perm(&selinux_state, sid, perfsec->sid,
+       return avc_has_perm(sid, perfsec->sid,
                            SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
 }
 #endif
 
+#ifdef CONFIG_IO_URING
+/**
+ * selinux_uring_override_creds - check the requested cred override
+ * @new: the target creds
+ *
+ * Check to see if the current task is allowed to override it's credentials
+ * to service an io_uring operation.
+ */
+static int selinux_uring_override_creds(const struct cred *new)
+{
+       return avc_has_perm(current_sid(), cred_sid(new),
+                           SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
+}
+
+/**
+ * selinux_uring_sqpoll - check if a io_uring polling thread can be created
+ *
+ * Check to see if the current task is allowed to create a new io_uring
+ * kernel polling thread.
+ */
+static int selinux_uring_sqpoll(void)
+{
+       u32 sid = current_sid();
+
+       return avc_has_perm(sid, sid,
+                           SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
+}
+
+/**
+ * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
+ * @ioucmd: the io_uring command structure
+ *
+ * Check to see if the current domain is allowed to execute an
+ * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
+ *
+ */
+static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+       struct file *file = ioucmd->file;
+       struct inode *inode = file_inode(file);
+       struct inode_security_struct *isec = selinux_inode(inode);
+       struct common_audit_data ad;
+
+       ad.type = LSM_AUDIT_DATA_FILE;
+       ad.u.file = file;
+
+       return avc_has_perm(current_sid(), isec->sid,
+                           SECCLASS_IO_URING, IO_URING__CMD, &ad);
+}
+#endif /* CONFIG_IO_URING */
+
+static const struct lsm_id selinux_lsmid = {
+       .name = "selinux",
+       .id = LSM_ID_SELINUX,
+};
+
 /*
  * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
  * 1. any hooks that don't belong to (2.) or (3.) below,
@@ -6942,12 +7130,8 @@ static int selinux_perf_event_write(struct perf_event *event)
  *    hooks ("allocating" hooks).
  *
  * Please follow block comment delimiters in the list to keep this order.
- *
- * This ordering is needed for SELinux runtime disable to work at least somewhat
- * safely. Breaking the ordering rules above might lead to NULL pointer derefs
- * when disabling SELinux at runtime.
  */
-static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list selinux_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
        LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
        LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
@@ -6969,8 +7153,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
        LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
 
-       LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
        LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
+       LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
        LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
        LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
        LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
@@ -6987,6 +7171,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
        LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
+       LSM_HOOK_INIT(inode_init_security_anon, selinux_inode_init_security_anon),
        LSM_HOOK_INIT(inode_create, selinux_inode_create),
        LSM_HOOK_INIT(inode_link, selinux_inode_link),
        LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
@@ -7005,6 +7190,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
        LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
        LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
+       LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl),
+       LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl),
+       LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl),
        LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
        LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
        LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
@@ -7018,6 +7206,7 @@ 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_ioctl, selinux_file_ioctl),
+       LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
        LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
        LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
        LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
@@ -7041,7 +7230,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
        LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
        LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
-       LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
+       LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj),
+       LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
        LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
        LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
        LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
@@ -7052,6 +7242,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
        LSM_HOOK_INIT(task_kill, selinux_task_kill),
        LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
+       LSM_HOOK_INIT(userns_create, selinux_userns_create),
 
        LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
        LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
@@ -7071,6 +7262,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
 
+       LSM_HOOK_INIT(getselfattr, selinux_getselfattr),
+       LSM_HOOK_INIT(setselfattr, selinux_setselfattr),
        LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
        LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
 
@@ -7109,6 +7302,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
        LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
        LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
+       LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
+       LSM_HOOK_INIT(mptcp_add_subflow, selinux_mptcp_add_subflow),
        LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
        LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
        LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
@@ -7157,8 +7352,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(bpf, selinux_bpf),
        LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
        LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
-       LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
-       LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+       LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free),
+       LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free),
+       LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free),
 #endif
 
 #ifdef CONFIG_PERF_EVENTS
@@ -7168,15 +7364,19 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
 #endif
 
-       LSM_HOOK_INIT(locked_down, selinux_lockdown),
+#ifdef CONFIG_IO_URING
+       LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
+       LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
+       LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
+#endif
 
        /*
         * PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE
         */
+       LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount),
        LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
        LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
        LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
-       LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt),
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
 #endif
@@ -7211,8 +7411,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
 #endif
 #ifdef CONFIG_BPF_SYSCALL
-       LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
-       LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+       LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create),
+       LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load),
+       LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create),
 #endif
 #ifdef CONFIG_PERF_EVENTS
        LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
@@ -7224,16 +7425,17 @@ static __init int selinux_init(void)
        pr_info("SELinux:  Initializing.\n");
 
        memset(&selinux_state, 0, sizeof(selinux_state));
-       enforcing_set(&selinux_state, selinux_enforcing_boot);
-       selinux_state.checkreqprot = selinux_checkreqprot_boot;
-       selinux_ss_init(&selinux_state.ss);
-       selinux_avc_init(&selinux_state.avc);
+       enforcing_set(selinux_enforcing_boot);
+       selinux_avc_init();
        mutex_init(&selinux_state.status_lock);
+       mutex_init(&selinux_state.policy_mutex);
 
        /* Set the security state for the initial task. */
        cred_init_security();
 
        default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
+       if (!default_noexec)
+               pr_notice("SELinux:  virtual memory is executable by default\n");
 
        avc_init();
 
@@ -7243,7 +7445,8 @@ static __init int selinux_init(void)
 
        hashtab_cache_init();
 
-       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
+       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
+                          &selinux_lsmid);
 
        if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
                panic("SELinux: Unable to register AVC netcache callback\n");
@@ -7286,41 +7489,40 @@ DEFINE_LSM(selinux) = {
 };
 
 #if defined(CONFIG_NETFILTER)
-
 static const struct nf_hook_ops selinux_nf_ops[] = {
        {
-               .hook =         selinux_ipv4_postroute,
+               .hook =         selinux_ip_postroute,
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP_PRI_SELINUX_LAST,
        },
        {
-               .hook =         selinux_ipv4_forward,
+               .hook =         selinux_ip_forward,
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
        },
        {
-               .hook =         selinux_ipv4_output,
+               .hook =         selinux_ip_output,
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_LOCAL_OUT,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
        },
 #if IS_ENABLED(CONFIG_IPV6)
        {
-               .hook =         selinux_ipv6_postroute,
+               .hook =         selinux_ip_postroute,
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP6_PRI_SELINUX_LAST,
        },
        {
-               .hook =         selinux_ipv6_forward,
+               .hook =         selinux_ip_forward,
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
        },
        {
-               .hook =         selinux_ipv6_output,
+               .hook =         selinux_ip_output,
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_LOCAL_OUT,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
@@ -7361,56 +7563,4 @@ static int __init selinux_nf_ip_init(void)
        return 0;
 }
 __initcall(selinux_nf_ip_init);
-
-#ifdef CONFIG_SECURITY_SELINUX_DISABLE
-static void selinux_nf_ip_exit(void)
-{
-       pr_debug("SELinux:  Unregistering netfilter hooks\n");
-
-       unregister_pernet_subsys(&selinux_net_ops);
-}
-#endif
-
-#else /* CONFIG_NETFILTER */
-
-#ifdef CONFIG_SECURITY_SELINUX_DISABLE
-#define selinux_nf_ip_exit()
-#endif
-
 #endif /* CONFIG_NETFILTER */
-
-#ifdef CONFIG_SECURITY_SELINUX_DISABLE
-int selinux_disable(struct selinux_state *state)
-{
-       if (selinux_initialized(state)) {
-               /* Not permitted after initial policy load. */
-               return -EINVAL;
-       }
-
-       if (selinux_disabled(state)) {
-               /* Only do this once. */
-               return -EINVAL;
-       }
-
-       selinux_mark_disabled(state);
-
-       pr_info("SELinux:  Disabled at runtime.\n");
-
-       /*
-        * Unregister netfilter hooks.
-        * Must be done before security_delete_hooks() to avoid breaking
-        * runtime disable.
-        */
-       selinux_nf_ip_exit();
-
-       security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
-
-       /* Try to destroy the avc node cache */
-       avc_disable();
-
-       /* Unregister selinuxfs. */
-       exit_sel_fs();
-
-       return 0;
-}
-#endif