SELinux: do not compute transition labels on mountpoint labeled filesystems
[linux-flexiantxendom0-natty.git] / security / selinux / hooks.c
index 853b58c..cda18fd 100644 (file)
@@ -13,8 +13,8 @@
  *                                        Eric Paris <eparis@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
- *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
- *             Paul Moore <paul.moore@hp.com>
+ *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
+ *     Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
@@ -76,6 +76,7 @@
 #include <linux/selinux.h>
 #include <linux/mutex.h>
 #include <linux/posix-timers.h>
+#include <linux/syslog.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "netlabel.h"
 #include "audit.h"
 
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+#define NUM_SEL_MNT_OPTS 5
 
-#define NUM_SEL_MNT_OPTS 4
-
-extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
-extern int selinux_compat_net;
 extern struct security_operations *security_ops;
 
 /* SECMARK reference count */
@@ -127,18 +123,6 @@ __setup("selinux=", selinux_enabled_setup);
 int selinux_enabled = 1;
 #endif
 
-
-/*
- * Minimal support for a secondary security module,
- * just to allow the use of the capability module.
- */
-static struct security_operations *secondary_ops;
-
-/* Lists of inode and superblock security structures initialized
-   before the policy was loaded. */
-static LIST_HEAD(superblock_security_head);
-static DEFINE_SPINLOCK(sb_security_lock);
-
 static struct kmem_cache *sel_inode_cache;
 
 /**
@@ -201,7 +185,7 @@ static inline u32 task_sid(const struct task_struct *task)
  */
 static inline u32 current_sid(void)
 {
-       const struct task_security_struct *tsec = current_cred()->security;
+       const struct task_security_struct *tsec = current_security();
 
        return tsec->sid;
 }
@@ -274,7 +258,6 @@ static int superblock_alloc_security(struct super_block *sb)
                return -ENOMEM;
 
        mutex_init(&sbsec->lock);
-       INIT_LIST_HEAD(&sbsec->list);
        INIT_LIST_HEAD(&sbsec->isec_head);
        spin_lock_init(&sbsec->isec_lock);
        sbsec->sb = sb;
@@ -289,49 +272,17 @@ static int superblock_alloc_security(struct super_block *sb)
 static void superblock_free_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
-
-       spin_lock(&sb_security_lock);
-       if (!list_empty(&sbsec->list))
-               list_del_init(&sbsec->list);
-       spin_unlock(&sb_security_lock);
-
        sb->s_security = NULL;
        kfree(sbsec);
 }
 
-static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
-{
-       struct sk_security_struct *ssec;
-
-       ssec = kzalloc(sizeof(*ssec), priority);
-       if (!ssec)
-               return -ENOMEM;
-
-       ssec->peer_sid = SECINITSID_UNLABELED;
-       ssec->sid = SECINITSID_UNLABELED;
-       sk->sk_security = ssec;
-
-       selinux_netlbl_sk_security_reset(ssec, family);
-
-       return 0;
-}
-
-static void sk_free_security(struct sock *sk)
-{
-       struct sk_security_struct *ssec = sk->sk_security;
-
-       sk->sk_security = NULL;
-       selinux_netlbl_sk_security_free(ssec);
-       kfree(ssec);
-}
-
 /* The security server must be initialized before
    any labeling or access decisions can be provided. */
 extern int ss_initialized;
 
 /* The file system's label must be initialized prior to use. */
 
-static char *labeling_behaviors[6] = {
+static const char *labeling_behaviors[6] = {
        "uses xattr",
        "uses transition SIDs",
        "uses task SIDs",
@@ -353,6 +304,7 @@ enum {
        Opt_fscontext = 2,
        Opt_defcontext = 3,
        Opt_rootcontext = 4,
+       Opt_labelsupport = 5,
 };
 
 static const match_table_t tokens = {
@@ -360,6 +312,7 @@ static const match_table_t tokens = {
        {Opt_fscontext, FSCONTEXT_STR "%s"},
        {Opt_defcontext, DEFCONTEXT_STR "%s"},
        {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
+       {Opt_labelsupport, LABELSUPP_STR},
        {Opt_error, NULL},
 };
 
@@ -431,7 +384,7 @@ static int sb_finish_set_opts(struct super_block *sb)
                }
        }
 
-       sbsec->initialized = 1;
+       sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
 
        if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
@@ -441,6 +394,16 @@ static int sb_finish_set_opts(struct super_block *sb)
                       sb->s_id, sb->s_type->name,
                       labeling_behaviors[sbsec->behavior-1]);
 
+       if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
+           sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
+           sbsec->behavior == SECURITY_FS_USE_NONE ||
+           sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+               sbsec->flags &= ~SE_SBLABELSUPP;
+
+       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
+       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+               sbsec->flags |= SE_SBLABELSUPP;
+
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
 
@@ -487,23 +450,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
 
        security_init_mnt_opts(opts);
 
-       if (!sbsec->initialized)
+       if (!(sbsec->flags & SE_SBINITIALIZED))
                return -EINVAL;
 
        if (!ss_initialized)
                return -EINVAL;
 
-       /*
-        * if we ever use sbsec flags for anything other than tracking mount
-        * settings this is going to need a mask
-        */
-       tmp = sbsec->flags;
+       tmp = sbsec->flags & SE_MNTMASK;
        /* count the number of mount options for this sb */
        for (i = 0; i < 8; i++) {
                if (tmp & 0x01)
                        opts->num_mnt_opts++;
                tmp >>= 1;
        }
+       /* Check if the Label support flag is set */
+       if (sbsec->flags & SE_SBLABELSUPP)
+               opts->num_mnt_opts++;
 
        opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
        if (!opts->mnt_opts) {
@@ -549,6 +511,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                opts->mnt_opts[i] = context;
                opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
        }
+       if (sbsec->flags & SE_SBLABELSUPP) {
+               opts->mnt_opts[i] = NULL;
+               opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
+       }
 
        BUG_ON(i != opts->num_mnt_opts);
 
@@ -562,8 +528,10 @@ out_free:
 static int bad_option(struct superblock_security_struct *sbsec, char flag,
                      u32 old_sid, u32 new_sid)
 {
+       char mnt_flags = sbsec->flags & SE_MNTMASK;
+
        /* check if the old mount command had the same options */
-       if (sbsec->initialized)
+       if (sbsec->flags & SE_SBINITIALIZED)
                if (!(sbsec->flags & flag) ||
                    (old_sid != new_sid))
                        return 1;
@@ -571,8 +539,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
        /* check if we were passed the same options twice,
         * aka someone passed context=a,context=b
         */
-       if (!sbsec->initialized)
-               if (sbsec->flags & flag)
+       if (!(sbsec->flags & SE_SBINITIALIZED))
+               if (mnt_flags & flag)
                        return 1;
        return 0;
 }
@@ -603,10 +571,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        /* Defer initialization until selinux_complete_init,
                           after the initial policy is loaded and the security
                           server is ready to handle calls. */
-                       spin_lock(&sb_security_lock);
-                       if (list_empty(&sbsec->list))
-                               list_add(&sbsec->list, &superblock_security_head);
-                       spin_unlock(&sb_security_lock);
                        goto out;
                }
                rc = -EINVAL;
@@ -626,7 +590,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         * this sb does not set any security options.  (The first options
         * will be used for both mounts)
         */
-       if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+       if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
            && (num_opts == 0))
                goto out;
 
@@ -637,6 +601,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        for (i = 0; i < num_opts; i++) {
                u32 sid;
+
+               if (flags[i] == SE_SBLABELSUPP)
+                       continue;
                rc = security_context_to_sid(mount_options[i],
                                             strlen(mount_options[i]), &sid);
                if (rc) {
@@ -690,19 +657,19 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                }
        }
 
-       if (sbsec->initialized) {
+       if (sbsec->flags & SE_SBINITIALIZED) {
                /* previously mounted with options, but not on this attempt? */
-               if (sbsec->flags && !num_opts)
+               if ((sbsec->flags & SE_MNTMASK) && !num_opts)
                        goto out_double_mount;
                rc = 0;
                goto out;
        }
 
        if (strcmp(sb->s_type->name, "proc") == 0)
-               sbsec->proc = 1;
+               sbsec->flags |= SE_SBPROC;
 
        /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
                       __func__, sb->s_type->name, rc);
@@ -794,22 +761,16 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 
        /*
         * if the parent was able to be mounted it clearly had no special lsm
-        * mount options.  thus we can safely put this sb on the list and deal
-        * with it later
+        * mount options.  thus we can safely deal with this superblock later
         */
-       if (!ss_initialized) {
-               spin_lock(&sb_security_lock);
-               if (list_empty(&newsbsec->list))
-                       list_add(&newsbsec->list, &superblock_security_head);
-               spin_unlock(&sb_security_lock);
+       if (!ss_initialized)
                return;
-       }
 
        /* how can we clone if the old one wasn't set up?? */
-       BUG_ON(!oldsbsec->initialized);
+       BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
 
        /* if fs is reusing a sb, just let its options stand... */
-       if (newsbsec->initialized)
+       if (newsbsec->flags & SE_SBINITIALIZED)
                return;
 
        mutex_lock(&newsbsec->lock);
@@ -917,7 +878,8 @@ static int selinux_parse_opts_str(char *options,
                                goto out_err;
                        }
                        break;
-
+               case Opt_labelsupport:
+                       break;
                default:
                        rc = -EINVAL;
                        printk(KERN_WARNING "SELinux:  unknown mount option\n");
@@ -999,7 +961,12 @@ static void selinux_write_opts(struct seq_file *m,
        char *prefix;
 
        for (i = 0; i < opts->num_mnt_opts; i++) {
-               char *has_comma = strchr(opts->mnt_opts[i], ',');
+               char *has_comma;
+
+               if (opts->mnt_opts[i])
+                       has_comma = strchr(opts->mnt_opts[i], ',');
+               else
+                       has_comma = NULL;
 
                switch (opts->mnt_opts_flags[i]) {
                case CONTEXT_MNT:
@@ -1014,6 +981,10 @@ static void selinux_write_opts(struct seq_file *m,
                case DEFCONTEXT_MNT:
                        prefix = DEFCONTEXT_STR;
                        break;
+               case SE_SBLABELSUPP:
+                       seq_putc(m, ',');
+                       seq_puts(m, LABELSUPP_STR);
+                       continue;
                default:
                        BUG();
                };
@@ -1209,7 +1180,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                goto out_unlock;
 
        sbsec = inode->i_sb->s_security;
-       if (!sbsec->initialized) {
+       if (!(sbsec->flags & SE_SBINITIALIZED)) {
                /* Defer initialization until selinux_complete_init,
                   after the initial policy is loaded and the security
                   server is ready to handle calls. */
@@ -1237,22 +1208,31 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        dentry = d_find_alias(inode);
                }
                if (!dentry) {
-                       printk(KERN_WARNING "SELinux: %s:  no dentry for dev=%s "
-                              "ino=%ld\n", __func__, inode->i_sb->s_id,
-                              inode->i_ino);
+                       /*
+                        * this is can be hit on boot when a file is accessed
+                        * before the policy is loaded.  When we load policy we
+                        * may find inodes that have no dentry on the
+                        * sbsec->isec_head list.  No reason to complain as these
+                        * will get fixed up the next time we go through
+                        * inode_doinit with a dentry, before these inodes could
+                        * be used again by userspace.
+                        */
                        goto out_unlock;
                }
 
                len = INITCONTEXTLEN;
-               context = kmalloc(len, GFP_NOFS);
+               context = kmalloc(len+1, GFP_NOFS);
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
                        goto out_unlock;
                }
+               context[len] = '\0';
                rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
                                           context, len);
                if (rc == -ERANGE) {
+                       kfree(context);
+
                        /* Need a larger buffer.  Query for the right size. */
                        rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
                                                   NULL, 0);
@@ -1260,14 +1240,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                dput(dentry);
                                goto out_unlock;
                        }
-                       kfree(context);
                        len = rc;
-                       context = kmalloc(len, GFP_NOFS);
+                       context = kmalloc(len+1, GFP_NOFS);
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
                                goto out_unlock;
                        }
+                       context[len] = '\0';
                        rc = inode->i_op->getxattr(dentry,
                                                   XATTR_NAME_SELINUX,
                                                   context, len);
@@ -1289,10 +1269,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                                             sbsec->def_sid,
                                                             GFP_NOFS);
                        if (rc) {
-                               printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
-                                      "returned %d for dev=%s ino=%ld\n",
-                                      __func__, context, -rc,
-                                      inode->i_sb->s_id, inode->i_ino);
+                               char *dev = inode->i_sb->s_id;
+                               unsigned long ino = inode->i_ino;
+
+                               if (rc == -EINVAL) {
+                                       if (printk_ratelimit())
+                                               printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
+                                                       "context=%s.  This indicates you may need to relabel the inode or the "
+                                                       "filesystem in question.\n", ino, dev, context);
+                               } else {
+                                       printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
+                                              "returned %d for dev=%s ino=%ld\n",
+                                              __func__, context, -rc, dev, ino);
+                               }
                                kfree(context);
                                /* Leave with the unlabeled SID */
                                rc = 0;
@@ -1326,7 +1315,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                /* Default to the fs superblock SID. */
                isec->sid = sbsec->sid;
 
-               if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
+               if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
                        struct proc_inode *proci = PROC_I(inode);
                        if (proci->pde) {
                                isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -1433,16 +1422,17 @@ static int current_has_perm(const struct task_struct *tsk,
 
 /* Check whether a task is allowed to use a capability. */
 static int task_has_capability(struct task_struct *tsk,
+                              const struct cred *cred,
                               int cap, int audit)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct av_decision avd;
        u16 sclass;
-       u32 sid = task_sid(tsk);
+       u32 sid = cred_sid(cred);
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
@@ -1481,12 +1471,14 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct avc_audit_data *adp)
+                         struct common_audit_data *adp)
 {
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid;
 
+       validate_creds(cred);
+
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -1495,7 +1487,7 @@ static int inode_has_perm(const struct cred *cred,
 
        if (!adp) {
                adp = &ad;
-               AVC_AUDIT_DATA_INIT(&ad, FS);
+               COMMON_AUDIT_DATA_INIT(&ad, FS);
                ad.u.fs.inode = inode;
        }
 
@@ -1511,9 +1503,9 @@ static inline int dentry_has_perm(const struct cred *cred,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
        return inode_has_perm(cred, inode, av, &ad);
@@ -1533,11 +1525,11 @@ static int file_has_perm(const struct cred *cred,
 {
        struct file_security_struct *fsec = file->f_security;
        struct inode *inode = file->f_path.dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = cred_sid(cred);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = file->f_path;
 
        if (sid != fsec->sid) {
@@ -1563,12 +1555,11 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        dsec = dir->i_security;
@@ -1577,7 +1568,7 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
@@ -1586,7 +1577,7 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
                if (rc)
                        return rc;
@@ -1621,7 +1612,7 @@ static int may_link(struct inode *dir,
 
 {
        struct inode_security_struct *dsec, *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int rc;
@@ -1629,7 +1620,7 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        av = DIR__SEARCH;
@@ -1664,7 +1655,7 @@ static inline int may_rename(struct inode *old_dir,
                             struct dentry *new_dentry)
 {
        struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int old_is_dir, new_is_dir;
@@ -1675,7 +1666,7 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        ad.u.fs.path.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
@@ -1717,7 +1708,7 @@ static inline int may_rename(struct inode *old_dir,
 static int superblock_has_perm(const struct cred *cred,
                               struct super_block *sb,
                               u32 perms,
-                              struct avc_audit_data *ad)
+                              struct common_audit_data *ad)
 {
        struct superblock_security_struct *sbsec;
        u32 sid = cred_sid(cred);
@@ -1785,36 +1776,20 @@ static inline u32 open_file_to_av(struct file *file)
 {
        u32 av = file_to_av(file);
 
-       if (selinux_policycap_openperm) {
-               mode_t mode = file->f_path.dentry->d_inode->i_mode;
-               /*
-                * lnk files and socks do not really have an 'open'
-                */
-               if (S_ISREG(mode))
-                       av |= FILE__OPEN;
-               else if (S_ISCHR(mode))
-                       av |= CHR_FILE__OPEN;
-               else if (S_ISBLK(mode))
-                       av |= BLK_FILE__OPEN;
-               else if (S_ISFIFO(mode))
-                       av |= FIFO_FILE__OPEN;
-               else if (S_ISDIR(mode))
-                       av |= DIR__OPEN;
-               else
-                       printk(KERN_ERR "SELinux: WARNING: inside %s with "
-                               "unknown mode:%o\n", __func__, mode);
-       }
+       if (selinux_policycap_openperm)
+               av |= FILE__OPEN;
+
        return av;
 }
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace_may_access(struct task_struct *child,
+static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
        int rc;
 
-       rc = secondary_ops->ptrace_may_access(child, mode);
+       rc = cap_ptrace_access_check(child, mode);
        if (rc)
                return rc;
 
@@ -1831,7 +1806,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
 {
        int rc;
 
-       rc = secondary_ops->ptrace_traceme(parent);
+       rc = cap_ptrace_traceme(parent);
        if (rc)
                return rc;
 
@@ -1847,7 +1822,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
        if (error)
                return error;
 
-       return secondary_ops->capget(target, effective, inheritable, permitted);
+       return cap_capget(target, effective, inheritable, permitted);
 }
 
 static int selinux_capset(struct cred *new, const struct cred *old,
@@ -1857,7 +1832,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
 {
        int error;
 
-       error = secondary_ops->capset(new, old,
+       error = cap_capset(new, old,
                                      effective, inheritable, permitted);
        if (error)
                return error;
@@ -1865,15 +1840,26 @@ static int selinux_capset(struct cred *new, const struct cred *old,
        return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
-static int selinux_capable(struct task_struct *tsk, int cap, int audit)
+/*
+ * (This comment used to live with the selinux_task_setuid hook,
+ * which was removed).
+ *
+ * Since setuid only affects the current process, and since the SELinux
+ * controls are not based on the Linux identity attributes, SELinux does not
+ * need to control this operation.  However, SELinux does control the use of
+ * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
+ */
+
+static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
+                          int cap, int audit)
 {
        int rc;
 
-       rc = secondary_ops->capable(tsk, cap, audit);
+       rc = cap_capable(tsk, cred, cap, audit);
        if (rc)
                return rc;
 
-       return task_has_capability(tsk, cap, audit);
+       return task_has_capability(tsk, cred, cap, audit);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -1924,10 +1910,6 @@ static int selinux_sysctl(ctl_table *table, int op)
        u32 tsid, sid;
        int rc;
 
-       rc = secondary_ops->sysctl(table, op);
-       if (rc)
-               return rc;
-
        sid = current_sid();
 
        rc = selinux_sysctl_get_sid(table, (op == 0001) ?
@@ -1995,25 +1977,22 @@ static int selinux_syslog(int type)
 {
        int rc;
 
-       rc = secondary_ops->syslog(type);
-       if (rc)
-               return rc;
-
        switch (type) {
-       case 3:         /* Read last kernel messages */
-       case 10:        /* Return size of the log buffer */
+       case SYSLOG_ACTION_READ_ALL:    /* Read last kernel messages */
+       case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
                rc = task_has_system(current, SYSTEM__SYSLOG_READ);
                break;
-       case 6:         /* Disable logging to console */
-       case 7:         /* Enable logging to console */
-       case 8:         /* Set level of messages printed to console */
+       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:
                rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
                break;
-       case 0:         /* Close log */
-       case 1:         /* Open log */
-       case 2:         /* Read from log */
-       case 4:         /* Read/clear last kernel messages */
-       case 5:         /* Clear ring buffer */
+       case SYSLOG_ACTION_CLOSE:       /* Close log */
+       case SYSLOG_ACTION_OPEN:        /* Open log */
+       case SYSLOG_ACTION_READ:        /* Read from log */
+       case SYSLOG_ACTION_READ_CLEAR:  /* Read/clear last kernel messages */
+       case SYSLOG_ACTION_CLEAR:       /* Clear ring buffer */
        default:
                rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
                break;
@@ -2026,10 +2005,6 @@ static int selinux_syslog(int type)
  * mapping. 0 means there is enough memory for the allocation to
  * succeed and -ENOMEM implies there is not.
  *
- * Note that secondary_ops->capable and task_has_perm_noaudit return 0
- * if the capability is granted, but __vm_enough_memory requires 1 if
- * the capability is granted.
- *
  * Do not audit the selinux permission check, as this is applied to all
  * processes that allocate mappings.
  */
@@ -2037,7 +2012,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
 
-       rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
+       rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
+                            SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
 
@@ -2051,11 +2027,11 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        const struct task_security_struct *old_tsec;
        struct task_security_struct *new_tsec;
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct inode *inode = bprm->file->f_path.dentry->d_inode;
        int rc;
 
-       rc = secondary_ops->bprm_set_creds(bprm);
+       rc = cap_bprm_set_creds(bprm);
        if (rc)
                return rc;
 
@@ -2089,7 +2065,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
@@ -2153,15 +2129,9 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        return 0;
 }
 
-static int selinux_bprm_check_security(struct linux_binprm *bprm)
-{
-       return secondary_ops->bprm_check_security(bprm);
-}
-
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        u32 sid, osid;
        int atsecure = 0;
 
@@ -2177,7 +2147,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
                                        PROCESS__NOATSECURE, NULL);
        }
 
-       return (atsecure || secondary_ops->bprm_secureexec(bprm));
+       return (atsecure || cap_bprm_secureexec(bprm));
 }
 
 extern struct vfsmount *selinuxfs_mount;
@@ -2187,7 +2157,7 @@ extern struct dentry *selinux_null;
 static inline void flush_unauthorized_files(const struct cred *cred,
                                            struct files_struct *files)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct file *file, *devnull = NULL;
        struct tty_struct *tty;
        struct fdtable *fdt;
@@ -2196,8 +2166,9 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        tty = get_current_tty();
        if (tty) {
-               file_list_lock();
+               spin_lock(&tty_files_lock);
                if (!list_empty(&tty->tty_files)) {
+                       struct tty_file_private *file_priv;
                        struct inode *inode;
 
                        /* Revalidate access to controlling tty.
@@ -2205,14 +2176,16 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                           than using file_has_perm, as this particular open
                           file may belong to another process and we are only
                           interested in the inode-based check here. */
-                       file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
+                       file_priv = list_first_entry(&tty->tty_files,
+                                               struct tty_file_private, list);
+                       file = file_priv->file;
                        inode = file->f_path.dentry->d_inode;
                        if (inode_has_perm(cred, inode,
                                           FILE__READ | FILE__WRITE, NULL)) {
                                drop_tty = 1;
                        }
                }
-               file_list_unlock();
+               spin_unlock(&tty_files_lock);
                tty_kref_put(tty);
        }
        /* Reset controlling tty. */
@@ -2221,7 +2194,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2287,8 +2260,6 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
        struct rlimit *rlim, *initrlim;
        int rc, i;
 
-       secondary_ops->bprm_committing_creds(bprm);
-
        new_tsec = bprm->cred->security;
        if (new_tsec->sid == new_tsec->osid)
                return;
@@ -2312,12 +2283,15 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
        rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
                          PROCESS__RLIMITINH, NULL);
        if (rc) {
+               /* protect against do_prlimit() */
+               task_lock(current);
                for (i = 0; i < RLIM_NLIMITS; i++) {
                        rlim = current->signal->rlim + i;
                        initrlim = init_task.signal->rlim + i;
                        rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
                }
-               update_rlimit_cpu(rlim->rlim_cur);
+               task_unlock(current);
+               update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
        }
 }
 
@@ -2329,12 +2303,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
        const struct task_security_struct *tsec = current_security();
        struct itimerval itimer;
-       struct sighand_struct *psig;
        u32 osid, sid;
        int rc, i;
-       unsigned long flags;
-
-       secondary_ops->bprm_committed_creds(bprm);
 
        osid = tsec->osid;
        sid = tsec->sid;
@@ -2354,22 +2324,20 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
                memset(&itimer, 0, sizeof itimer);
                for (i = 0; i < 3; i++)
                        do_setitimer(i, &itimer, NULL);
-               flush_signals(current);
                spin_lock_irq(&current->sighand->siglock);
-               flush_signal_handlers(current, 1);
-               sigemptyset(&current->blocked);
-               recalc_sigpending();
+               if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
+                       __flush_signals(current);
+                       flush_signal_handlers(current, 1);
+                       sigemptyset(&current->blocked);
+               }
                spin_unlock_irq(&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_irq(&tasklist_lock);
-       psig = current->parent->sighand;
-       spin_lock_irqsave(&psig->siglock, flags);
-       wake_up_interruptible(&current->parent->signal->wait_chldexit);
-       spin_unlock_irqrestore(&psig->siglock, flags);
-       read_unlock_irq(&tasklist_lock);
+       read_lock(&tasklist_lock);
+       __wake_up_parent(current, current->real_parent);
+       read_unlock(&tasklist_lock);
 }
 
 /* superblock security operations */
@@ -2397,7 +2365,8 @@ static inline int selinux_option(char *option, int len)
        return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
                match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
                match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
-               match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
+               match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
+               match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -2477,7 +2446,7 @@ out:
 static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        rc = superblock_doinit(sb, data);
@@ -2488,7 +2457,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2496,9 +2465,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 static int selinux_sb_statfs(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
@@ -2510,11 +2479,6 @@ static int selinux_mount(char *dev_name,
                         void *data)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
-       if (rc)
-               return rc;
 
        if (flags & MS_REMOUNT)
                return superblock_has_perm(cred, path->mnt->mnt_sb,
@@ -2527,11 +2491,6 @@ static int selinux_mount(char *dev_name,
 static int selinux_umount(struct vfsmount *mnt, int flags)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->sb_umount(mnt, flags);
-       if (rc)
-               return rc;
 
        return superblock_has_perm(cred, mnt->mnt_sb,
                                   FILESYSTEM__UNMOUNT, NULL);
@@ -2553,8 +2512,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       char **name, void **value,
                                       size_t *len)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
@@ -2567,7 +2525,10 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+       if ((sbsec->flags & SE_SBINITIALIZED) &&
+           (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
+               newsid = sbsec->mntpoint_sid;
+       else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
                                             &newsid);
@@ -2582,14 +2543,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        /* Possibly defer initialization to selinux_complete_init. */
-       if (sbsec->initialized) {
+       if (sbsec->flags & SE_SBINITIALIZED) {
                struct inode_security_struct *isec = inode->i_security;
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
                isec->sid = newsid;
                isec->initialized = 1;
        }
 
-       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
        if (name) {
@@ -2619,21 +2580,11 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma
 
 static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
-       int rc;
-
-       rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
-       if (rc)
-               return rc;
        return may_link(dir, old_dentry, MAY_LINK);
 }
 
 static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
 {
-       int rc;
-
-       rc = secondary_ops->inode_unlink(dir, dentry);
-       if (rc)
-               return rc;
        return may_link(dir, dentry, MAY_UNLINK);
 }
 
@@ -2654,12 +2605,6 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
 
 static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-       int rc;
-
-       rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
-       if (rc)
-               return rc;
-
        return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
 
@@ -2679,46 +2624,50 @@ static int selinux_inode_readlink(struct dentry *dentry)
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
        const struct cred *cred = current_cred();
-       int rc;
 
-       rc = secondary_ops->inode_follow_link(dentry, nameidata);
-       if (rc)
-               return rc;
        return dentry_has_perm(cred, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
        const struct cred *cred = current_cred();
-       int rc;
+       struct common_audit_data ad;
+       u32 perms;
+       bool from_access;
 
-       rc = secondary_ops->inode_permission(inode, mask);
-       if (rc)
-               return rc;
+       from_access = mask & MAY_ACCESS;
+       mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
+       /* No permission to check.  Existence test. */
+       if (!mask)
                return 0;
-       }
 
-       return inode_has_perm(cred, inode,
-                             file_mask_to_av(inode->i_mode, mask), NULL);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       ad.u.fs.inode = inode;
+
+       if (from_access)
+               ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+       perms = file_mask_to_av(inode->i_mode, mask);
+
+       return inode_has_perm(cred, inode, perms, &ad);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->inode_setattr(dentry, iattr);
-       if (rc)
-               return rc;
-
-       if (iattr->ia_valid & ATTR_FORCE)
-               return 0;
+       unsigned int ia_valid = iattr->ia_valid;
+
+       /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
+       if (ia_valid & ATTR_FORCE) {
+               ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
+                             ATTR_FORCE);
+               if (!ia_valid)
+                       return 0;
+       }
 
-       if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
-                              ATTR_ATIME_SET | ATTR_MTIME_SET))
+       if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
+                       ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 
        return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
@@ -2758,7 +2707,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 newsid, sid = current_sid();
        int rc = 0;
 
@@ -2766,13 +2715,13 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return selinux_inode_setotherxattr(dentry, name);
 
        sbsec = inode->i_sb->s_security;
-       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (!(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
        if (!is_owner_or_cap(inode))
                return -EPERM;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
@@ -2880,7 +2829,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
+       error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
+                               SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
                                                      &size);
@@ -2916,6 +2866,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                return rc;
 
        isec->sid = newsid;
+       isec->initialized = 1;
        return 0;
 }
 
@@ -2927,16 +2878,6 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
        return len;
 }
 
-static int selinux_inode_need_killpriv(struct dentry *dentry)
-{
-       return secondary_ops->inode_need_killpriv(dentry);
-}
-
-static int selinux_inode_killpriv(struct dentry *dentry)
-{
-       return secondary_ops->inode_killpriv(dentry);
-}
-
 static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
 {
        struct inode_security_struct *isec = inode->i_security;
@@ -2948,24 +2889,14 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
 static int selinux_revalidate_file_permission(struct file *file, int mask)
 {
        const struct cred *cred = current_cred();
-       int rc;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
-               return 0;
-       }
-
        /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
 
-       rc = file_has_perm(cred, file,
-                          file_mask_to_av(inode->i_mode, mask));
-       if (rc)
-               return rc;
-
-       return selinux_netlbl_inode_permission(inode, mask);
+       return file_has_perm(cred, file,
+                            file_mask_to_av(inode->i_mode, mask));
 }
 
 static int selinux_file_permission(struct file *file, int mask)
@@ -2975,14 +2906,14 @@ static int selinux_file_permission(struct file *file, int mask)
        struct inode_security_struct *isec = inode->i_security;
        u32 sid = current_sid();
 
-       if (!mask) {
+       if (!mask)
                /* No permission to check.  Existence test. */
                return 0;
-       }
 
-       if (sid == fsec->sid && fsec->isid == isec->sid
-           && fsec->pseqno == avc_policy_seqno())
-               return selinux_netlbl_inode_permission(inode, mask);
+       if (sid == fsec->sid && fsec->isid == isec->sid &&
+           fsec->pseqno == avc_policy_seqno())
+               /* No change since dentry_open check. */
+               return 0;
 
        return selinux_revalidate_file_permission(file, mask);
 }
@@ -3013,13 +2944,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        return file_has_perm(cred, file, av);
 }
 
+static int default_noexec;
+
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
        const struct cred *cred = current_cred();
        int rc = 0;
 
-#ifndef CONFIG_PPC32
-       if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
+       if (default_noexec &&
+           (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
                /*
                 * We are making executable an anonymous mapping or a
                 * private file mapping that will also be writable.
@@ -3029,7 +2962,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                if (rc)
                        goto error;
        }
-#endif
 
        if (file) {
                /* read access is always possible with a mapping */
@@ -3056,9 +2988,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
        int rc = 0;
        u32 sid = current_sid();
 
-       if (addr < mmap_min_addr)
+       /*
+        * notice that we are intentionally putting the SELinux check before
+        * the secondary cap_file_mmap check.  This is such a likely attempt
+        * at bad behaviour/exploit that we always want to get the AVC, even
+        * if DAC would have also denied the operation.
+        */
+       if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
                                  MEMPROTECT__MMAP_ZERO, NULL);
+               if (rc)
+                       return rc;
+       }
+
+       /* do DAC check on address space usage */
+       rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
        if (rc || addr_only)
                return rc;
 
@@ -3074,18 +3018,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                                 unsigned long prot)
 {
        const struct cred *cred = current_cred();
-       int rc;
-
-       rc = secondary_ops->file_mprotect(vma, reqprot, prot);
-       if (rc)
-               return rc;
 
        if (selinux_checkreqprot)
                prot = reqprot;
 
-#ifndef CONFIG_PPC32
-       if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
-               rc = 0;
+       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 = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
@@ -3106,7 +3045,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                if (rc)
                        return rc;
        }
-#endif
 
        return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
 }
@@ -3177,7 +3115,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
                                       struct fown_struct *fown, int signum)
 {
        struct file *file;
-       u32 sid = current_sid();
+       u32 sid = task_sid(tsk);
        u32 perm;
        struct file_security_struct *fsec;
 
@@ -3235,13 +3173,22 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
 
 static int selinux_task_create(unsigned long clone_flags)
 {
-       int rc;
+       return current_has_perm(current, PROCESS__FORK);
+}
 
-       rc = secondary_ops->task_create(clone_flags);
-       if (rc)
-               return rc;
+/*
+ * allocate the SELinux part of blank credentials
+ */
+static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       struct task_security_struct *tsec;
 
-       return current_has_perm(current, PROCESS__FORK);
+       tsec = kzalloc(sizeof(struct task_security_struct), gfp);
+       if (!tsec)
+               return -ENOMEM;
+
+       cred->security = tsec;
+       return 0;
 }
 
 /*
@@ -3250,7 +3197,9 @@ static int selinux_task_create(unsigned long clone_flags)
 static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
-       cred->security = NULL;
+
+       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
 
@@ -3274,11 +3223,14 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
 }
 
 /*
- * commit new credentials
+ * transfer the SELinux data to a blank set of creds
  */
-static void selinux_cred_commit(struct cred *new, const struct cred *old)
+static void selinux_cred_transfer(struct cred *new, const struct cred *old)
 {
-       secondary_ops->cred_commit(new, old);
+       const struct task_security_struct *old_tsec = old->security;
+       struct task_security_struct *tsec = new->security;
+
+       *tsec = *old_tsec;
 }
 
 /*
@@ -3322,30 +3274,21 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 
        if (ret == 0)
                tsec->create_sid = isec->sid;
-       return 0;
+       return ret;
 }
 
-static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+static int selinux_kernel_module_request(char *kmod_name)
 {
-       /* Since setuid only affects the current process, and
-          since the SELinux controls are not based on the Linux
-          identity attributes, SELinux does not need to control
-          this operation.  However, SELinux does control the use
-          of the CAP_SETUID and CAP_SETGID capabilities using the
-          capable hook. */
-       return 0;
-}
+       u32 sid;
+       struct common_audit_data ad;
 
-static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
-                                  int flags)
-{
-       return secondary_ops->task_fix_setuid(new, old, flags);
-}
+       sid = task_sid(current);
 
-static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
-{
-       /* See the comment for setuid above. */
-       return 0;
+       COMMON_AUDIT_DATA_INIT(&ad, KMOD);
+       ad.u.kmod_name = kmod_name;
+
+       return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
+                           SYSTEM__MODULE_REQUEST, &ad);
 }
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
@@ -3368,17 +3311,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
        *secid = task_sid(p);
 }
 
-static int selinux_task_setgroups(struct group_info *group_info)
-{
-       /* See the comment for setuid above. */
-       return 0;
-}
-
 static int selinux_task_setnice(struct task_struct *p, int nice)
 {
        int rc;
 
-       rc = secondary_ops->task_setnice(p, nice);
+       rc = cap_task_setnice(p, nice);
        if (rc)
                return rc;
 
@@ -3389,7 +3326,7 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio)
 {
        int rc;
 
-       rc = secondary_ops->task_setioprio(p, ioprio);
+       rc = cap_task_setioprio(p, ioprio);
        if (rc)
                return rc;
 
@@ -3401,30 +3338,26 @@ static int selinux_task_getioprio(struct task_struct *p)
        return current_has_perm(p, PROCESS__GETSCHED);
 }
 
-static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
+               struct rlimit *new_rlim)
 {
-       struct rlimit *old_rlim = current->signal->rlim + resource;
-       int rc;
-
-       rc = secondary_ops->task_setrlimit(resource, new_rlim);
-       if (rc)
-               return rc;
+       struct rlimit *old_rlim = p->signal->rlim + resource;
 
        /* Control the ability to change the hard limit (whether
           lowering or raising it), so that the hard limit can
           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 current_has_perm(current, PROCESS__SETRLIMIT);
+               return current_has_perm(p, PROCESS__SETRLIMIT);
 
        return 0;
 }
 
-static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
+static int selinux_task_setscheduler(struct task_struct *p)
 {
        int rc;
 
-       rc = secondary_ops->task_setscheduler(p, policy, lp);
+       rc = cap_task_setscheduler(p);
        if (rc)
                return rc;
 
@@ -3447,10 +3380,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        u32 perm;
        int rc;
 
-       rc = secondary_ops->task_kill(p, info, sig, secid);
-       if (rc)
-               return rc;
-
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
@@ -3463,18 +3392,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        return rc;
 }
 
-static int selinux_task_prctl(int option,
-                             unsigned long arg2,
-                             unsigned long arg3,
-                             unsigned long arg4,
-                             unsigned long arg5)
-{
-       /* The current prctl operations do not appear to require
-          any SELinux controls since they merely observe or modify
-          the state of the current process. */
-       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
-}
-
 static int selinux_task_wait(struct task_struct *p)
 {
        return task_has_perm(p, current, PROCESS__SIGCHLD);
@@ -3492,7 +3409,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv4(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        int offset, ihlen, ret = -EINVAL;
        struct iphdr _iph, *ih;
@@ -3573,7 +3490,7 @@ out:
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv6(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        u8 nexthdr;
        int ret = -EINVAL, offset;
@@ -3644,7 +3561,7 @@ out:
 
 #endif /* IPV6 */
 
-static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
+static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
                             char **_addrp, int src, u8 *proto)
 {
        char *addrp;
@@ -3722,71 +3639,54 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
 }
 
 /* socket security operations */
-static int socket_has_perm(struct task_struct *task, struct socket *sock,
-                          u32 perms)
+
+static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
 {
-       struct inode_security_struct *isec;
-       struct avc_audit_data ad;
-       u32 sid;
-       int err = 0;
+       return tsec->sockcreate_sid ? : tsec->sid;
+}
 
-       isec = SOCK_INODE(sock)->i_security;
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct common_audit_data ad;
+       u32 tsid = task_sid(task);
 
-       if (isec->sid == SECINITSID_KERNEL)
-               goto out;
-       sid = task_sid(task);
+       if (sksec->sid == SECINITSID_KERNEL)
+               return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.sk = sock->sk;
-       err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.sk = sk;
 
-out:
-       return err;
+       return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
 
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
-       u32 sid, newsid;
+       const struct task_security_struct *tsec = current_security();
+       u32 newsid;
        u16 secclass;
-       int err = 0;
 
        if (kern)
-               goto out;
-
-       sid = tsec->sid;
-       newsid = tsec->sockcreate_sid ?: sid;
+               return 0;
 
+       newsid = socket_sockcreate_sid(tsec);
        secclass = socket_type_to_security_class(family, type, protocol);
-       err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);
-
-out:
-       return err;
+       return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
 }
 
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
-       struct inode_security_struct *isec;
+       const struct task_security_struct *tsec = current_security();
+       struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
        struct sk_security_struct *sksec;
-       u32 sid, newsid;
        int err = 0;
 
-       sid = tsec->sid;
-       newsid = tsec->sockcreate_sid;
-
-       isec = SOCK_INODE(sock)->i_security;
-
        if (kern)
                isec->sid = SECINITSID_KERNEL;
-       else if (newsid)
-               isec->sid = newsid;
        else
-               isec->sid = sid;
+               isec->sid = socket_sockcreate_sid(tsec);
 
        isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->initialized = 1;
@@ -3795,7 +3695,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
                sksec = sock->sk->sk_security;
                sksec->sid = isec->sid;
                sksec->sclass = isec->sclass;
-               err = selinux_netlbl_socket_post_create(sock);
+               err = selinux_netlbl_socket_post_create(sock->sk, family);
        }
 
        return err;
@@ -3807,10 +3707,11 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        u16 family;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__BIND);
+       err = sock_has_perm(current, sk, SOCKET__BIND);
        if (err)
                goto out;
 
@@ -3819,19 +3720,16 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
         * Multiple address binding for SCTP is not supported yet: we just
         * check the first address now.
         */
-       family = sock->sk->sk_family;
+       family = sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
-               struct inode_security_struct *isec;
-               struct avc_audit_data ad;
+               struct sk_security_struct *sksec = sk->sk_security;
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
-               struct sock *sk = sock->sk;
                u32 sid, node_perm;
 
-               isec = SOCK_INODE(sock)->i_security;
-
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
@@ -3852,18 +3750,18 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                                      snum, &sid);
                                if (err)
                                        goto out;
-                               AVC_AUDIT_DATA_INIT(&ad, NET);
+                               COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
-                               err = avc_has_perm(isec->sid, sid,
-                                                  isec->sclass,
+                               err = avc_has_perm(sksec->sid, sid,
+                                                  sksec->sclass,
                                                   SOCKET__NAME_BIND, &ad);
                                if (err)
                                        goto out;
                        }
                }
 
-               switch (isec->sclass) {
+               switch (sksec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
@@ -3885,7 +3783,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (err)
                        goto out;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.sport = htons(snum);
                ad.u.net.family = family;
 
@@ -3894,8 +3792,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                else
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
-               err = avc_has_perm(isec->sid, sid,
-                                  isec->sclass, node_perm, &ad);
+               err = avc_has_perm(sksec->sid, sid,
+                                  sksec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3906,20 +3804,19 @@ out:
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sk->sk_security;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__CONNECT);
+       err = sock_has_perm(current, sk, SOCKET__CONNECT);
        if (err)
                return err;
 
        /*
         * If a TCP or DCCP socket, check name_connect permission for the port.
         */
-       isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass == SECCLASS_TCP_SOCKET ||
-           isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct avc_audit_data ad;
+       if (sksec->sclass == SECCLASS_TCP_SOCKET ||
+           sksec->sclass == SECCLASS_DCCP_SOCKET) {
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
@@ -3941,13 +3838,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                if (err)
                        goto out;
 
-               perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+               perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
-               err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+               err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
                if (err)
                        goto out;
        }
@@ -3960,7 +3857,7 @@ out:
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
 {
-       return socket_has_perm(current, sock, SOCKET__LISTEN);
+       return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
 }
 
 static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -3969,7 +3866,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        struct inode_security_struct *isec;
        struct inode_security_struct *newisec;
 
-       err = socket_has_perm(current, sock, SOCKET__ACCEPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
 
@@ -3986,36 +3883,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       int rc;
-
-       rc = socket_has_perm(current, sock, SOCKET__WRITE);
-       if (rc)
-               return rc;
-
-       return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
+       return sock_has_perm(current, sock->sk, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                                  int size, int flags)
 {
-       return socket_has_perm(current, sock, SOCKET__READ);
+       return sock_has_perm(current, sock->sk, SOCKET__READ);
 }
 
 static int selinux_socket_getsockname(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_getpeername(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__SETOPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
        if (err)
                return err;
 
@@ -4025,77 +3916,63 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
 static int selinux_socket_getsockopt(struct socket *sock, int level,
                                     int optname)
 {
-       return socket_has_perm(current, sock, SOCKET__GETOPT);
+       return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
 }
 
 static int selinux_socket_shutdown(struct socket *sock, int how)
 {
-       return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
+       return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock,
                                              struct socket *other,
                                              struct sock *newsk)
 {
-       struct sk_security_struct *ssec;
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
+       struct sk_security_struct *sksec_sock = sock->sk->sk_security;
+       struct sk_security_struct *sksec_other = other->sk->sk_security;
+       struct sk_security_struct *sksec_new = newsk->sk_security;
+       struct common_audit_data ad;
        int err;
 
-       err = secondary_ops->unix_stream_connect(sock, other, newsk);
-       if (err)
-               return err;
-
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
-
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
-       err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass,
+       err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+                          sksec_other->sclass,
                           UNIX_STREAM_SOCKET__CONNECTTO, &ad);
        if (err)
                return err;
 
-       /* connecting socket */
-       ssec = sock->sk->sk_security;
-       ssec->peer_sid = other_isec->sid;
-
        /* server child socket */
-       ssec = newsk->sk_security;
-       ssec->peer_sid = isec->sid;
-       err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
+       sksec_new->peer_sid = sksec_sock->sid;
+       err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
+                                   &sksec_new->sid);
+       if (err)
+               return err;
 
-       return err;
+       /* connecting socket */
+       sksec_sock->peer_sid = sksec_new->sid;
+
+       return 0;
 }
 
 static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
 {
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
-       int err;
+       struct sk_security_struct *ssec = sock->sk->sk_security;
+       struct sk_security_struct *osec = other->sk->sk_security;
+       struct common_audit_data ad;
 
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
-
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
-       err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass, SOCKET__SENDTO, &ad);
-       if (err)
-               return err;
-
-       return 0;
+       return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+                           &ad);
 }
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
                                    u32 peer_sid,
-                                   struct avc_audit_data *ad)
+                                   struct common_audit_data *ad)
 {
        int err;
        u32 if_sid;
@@ -4116,97 +3993,29 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
                            SECCLASS_NODE, NODE__RECVFROM, ad);
 }
 
-static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
-                                               struct sk_buff *skb,
-                                               struct avc_audit_data *ad,
-                                               u16 family,
-                                               char *addrp)
-{
-       int err;
-       struct sk_security_struct *sksec = sk->sk_security;
-       u16 sk_class;
-       u32 netif_perm, node_perm, recv_perm;
-       u32 port_sid, node_sid, if_sid, sk_sid;
-
-       sk_sid = sksec->sid;
-       sk_class = sksec->sclass;
-
-       switch (sk_class) {
-       case SECCLASS_UDP_SOCKET:
-               netif_perm = NETIF__UDP_RECV;
-               node_perm = NODE__UDP_RECV;
-               recv_perm = UDP_SOCKET__RECV_MSG;
-               break;
-       case SECCLASS_TCP_SOCKET:
-               netif_perm = NETIF__TCP_RECV;
-               node_perm = NODE__TCP_RECV;
-               recv_perm = TCP_SOCKET__RECV_MSG;
-               break;
-       case SECCLASS_DCCP_SOCKET:
-               netif_perm = NETIF__DCCP_RECV;
-               node_perm = NODE__DCCP_RECV;
-               recv_perm = DCCP_SOCKET__RECV_MSG;
-               break;
-       default:
-               netif_perm = NETIF__RAWIP_RECV;
-               node_perm = NODE__RAWIP_RECV;
-               recv_perm = 0;
-               break;
-       }
-
-       err = sel_netif_sid(skb->iif, &if_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
-       if (err)
-               return err;
-
-       err = sel_netnode_sid(addrp, family, &node_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
-       if (err)
-               return err;
-
-       if (!recv_perm)
-               return 0;
-       err = sel_netport_sid(sk->sk_protocol,
-                             ntohs(ad->u.net.sport), &port_sid);
-       if (unlikely(err)) {
-               printk(KERN_WARNING
-                      "SELinux: failure in"
-                      " selinux_sock_rcv_skb_iptables_compat(),"
-                      " network port label not found\n");
-               return err;
-       }
-       return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
-}
-
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                                       u16 family)
 {
-       int err;
+       int err = 0;
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
                return err;
 
-       if (selinux_compat_net)
-               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
-                                                          family, addrp);
-       else
+       if (selinux_secmark_enabled()) {
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
-       if (err)
-               return err;
+               if (err)
+                       return err;
+       }
 
        if (selinux_policycap_netpeer) {
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4232,7 +4041,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        struct sk_security_struct *sksec = sk->sk_security;
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4248,7 +4057,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
         * to the selinux_sock_rcv_skb_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_compat_net || !selinux_policycap_netpeer)
+       if (!selinux_policycap_netpeer)
                return selinux_sock_rcv_skb_compat(sk, skb, family);
 
        secmark_active = selinux_secmark_enabled();
@@ -4256,8 +4065,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!secmark_active && !peerlbl_active)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
@@ -4269,7 +4078,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
                if (err)
                        return err;
-               err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
+               err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
                                               peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 0);
@@ -4297,26 +4106,18 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
        int err = 0;
        char *scontext;
        u32 scontext_len;
-       struct sk_security_struct *ssec;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sock->sk->sk_security;
        u32 peer_sid = SECSID_NULL;
 
-       isec = SOCK_INODE(sock)->i_security;
-
-       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
-           isec->sclass == SECCLASS_TCP_SOCKET) {
-               ssec = sock->sk->sk_security;
-               peer_sid = ssec->peer_sid;
-       }
-       if (peer_sid == SECSID_NULL) {
-               err = -ENOPROTOOPT;
-               goto out;
-       }
+       if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+           sksec->sclass == SECCLASS_TCP_SOCKET)
+               peer_sid = sksec->peer_sid;
+       if (peer_sid == SECSID_NULL)
+               return -ENOPROTOOPT;
 
        err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
        if (err)
-               goto out;
+               return err;
 
        if (scontext_len > len) {
                err = -ERANGE;
@@ -4329,9 +4130,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
 out_len:
        if (put_user(scontext_len, optlen))
                err = -EFAULT;
-
        kfree(scontext);
-out:
        return err;
 }
 
@@ -4363,24 +4162,39 @@ out:
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-       return sk_alloc_security(sk, family, priority);
+       struct sk_security_struct *sksec;
+
+       sksec = kzalloc(sizeof(*sksec), priority);
+       if (!sksec)
+               return -ENOMEM;
+
+       sksec->peer_sid = SECINITSID_UNLABELED;
+       sksec->sid = SECINITSID_UNLABELED;
+       selinux_netlbl_sk_security_reset(sksec);
+       sk->sk_security = sksec;
+
+       return 0;
 }
 
 static void selinux_sk_free_security(struct sock *sk)
 {
-       sk_free_security(sk);
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       sk->sk_security = NULL;
+       selinux_netlbl_sk_security_free(sksec);
+       kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
 {
-       struct sk_security_struct *ssec = sk->sk_security;
-       struct sk_security_struct *newssec = newsk->sk_security;
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *newsksec = newsk->sk_security;
 
-       newssec->sid = ssec->sid;
-       newssec->peer_sid = ssec->peer_sid;
-       newssec->sclass = ssec->sclass;
+       newsksec->sid = sksec->sid;
+       newsksec->peer_sid = sksec->peer_sid;
+       newsksec->sclass = sksec->sclass;
 
-       selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
+       selinux_netlbl_sk_security_reset(newsksec);
 }
 
 static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4424,16 +4238,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        if (peersid == SECSID_NULL) {
                req->secid = sksec->sid;
                req->peer_secid = SECSID_NULL;
-               return 0;
+       } else {
+               err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
+               if (err)
+                       return err;
+               req->secid = newsid;
+               req->peer_secid = peersid;
        }
 
-       err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
-       if (err)
-               return err;
-
-       req->secid = newsid;
-       req->peer_secid = peersid;
-       return 0;
+       return selinux_netlbl_inet_conn_request(req, family);
 }
 
 static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4450,7 +4263,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
 
        /* We don't need to take any sort of lock here as we are the only
         * thread with access to newsksec */
-       selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
+       selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
 }
 
 static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4463,8 +4276,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
                family = PF_INET;
 
        selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+}
+
+static int selinux_secmark_relabel_packet(u32 sid)
+{
+       const struct task_security_struct *__tsec;
+       u32 tsid;
+
+       __tsec = current_security();
+       tsid = __tsec->sid;
+
+       return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
+}
 
-       selinux_netlbl_inet_conn_established(sk, family);
+static void selinux_secmark_refcount_inc(void)
+{
+       atomic_inc(&selinux_secmark_refcount);
+}
+
+static void selinux_secmark_refcount_dec(void)
+{
+       atomic_dec(&selinux_secmark_refcount);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4473,13 +4305,65 @@ static void selinux_req_classify_flow(const struct request_sock *req,
        fl->secid = req->secid;
 }
 
+static int selinux_tun_dev_create(void)
+{
+       u32 sid = current_sid();
+
+       /* we aren't taking into account the "sockcreate" SID since the socket
+        * that is being created here is not a socket in the traditional sense,
+        * instead it is a private sock, accessible only to the kernel, and
+        * representing a wide range of network traffic spanning multiple
+        * connections unlike traditional sockets - check the TUN driver to
+        * get a better understanding of why this socket is special */
+
+       return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+                           NULL);
+}
+
+static void selinux_tun_dev_post_create(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       /* we don't currently perform any NetLabel based labeling here and it
+        * isn't clear that we would want to do so anyway; while we could apply
+        * labeling without the support of the TUN user the resulting labeled
+        * traffic from the other end of the connection would almost certainly
+        * cause confusion to the TUN user that had no idea network labeling
+        * protocols were being used */
+
+       /* see the comments in selinux_tun_dev_create() about why we don't use
+        * the sockcreate SID here */
+
+       sksec->sid = current_sid();
+       sksec->sclass = SECCLASS_TUN_SOCKET;
+}
+
+static int selinux_tun_dev_attach(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       u32 sid = current_sid();
+       int err;
+
+       err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELFROM, NULL);
+       if (err)
+               return err;
+       err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELTO, NULL);
+       if (err)
+               return err;
+
+       sksec->sid = sid;
+
+       return 0;
+}
+
 static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
 {
        int err = 0;
        u32 perm;
        struct nlmsghdr *nlh;
-       struct socket *sock = sk->sk_socket;
-       struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+       struct sk_security_struct *sksec = sk->sk_security;
 
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
@@ -4487,13 +4371,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        }
        nlh = nlmsg_hdr(skb);
 
-       err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+       err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
                        audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
-                                 nlh->nlmsg_type, isec->sclass);
+                                 nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
@@ -4504,7 +4388,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
                goto out;
        }
 
-       err = socket_has_perm(current, sock, perm);
+       err = sock_has_perm(current, sk, perm);
 out:
        return err;
 }
@@ -4517,7 +4401,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        int err;
        char *addrp;
        u32 peer_sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u8 secmark_active;
        u8 netlbl_active;
        u8 peerlbl_active;
@@ -4534,7 +4418,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
                return NF_DROP;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
@@ -4616,78 +4500,13 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum,
        return selinux_ip_output(skb, PF_INET);
 }
 
-static int selinux_ip_postroute_iptables_compat(struct sock *sk,
-                                               int ifindex,
-                                               struct avc_audit_data *ad,
-                                               u16 family, char *addrp)
-{
-       int err;
-       struct sk_security_struct *sksec = sk->sk_security;
-       u16 sk_class;
-       u32 netif_perm, node_perm, send_perm;
-       u32 port_sid, node_sid, if_sid, sk_sid;
-
-       sk_sid = sksec->sid;
-       sk_class = sksec->sclass;
-
-       switch (sk_class) {
-       case SECCLASS_UDP_SOCKET:
-               netif_perm = NETIF__UDP_SEND;
-               node_perm = NODE__UDP_SEND;
-               send_perm = UDP_SOCKET__SEND_MSG;
-               break;
-       case SECCLASS_TCP_SOCKET:
-               netif_perm = NETIF__TCP_SEND;
-               node_perm = NODE__TCP_SEND;
-               send_perm = TCP_SOCKET__SEND_MSG;
-               break;
-       case SECCLASS_DCCP_SOCKET:
-               netif_perm = NETIF__DCCP_SEND;
-               node_perm = NODE__DCCP_SEND;
-               send_perm = DCCP_SOCKET__SEND_MSG;
-               break;
-       default:
-               netif_perm = NETIF__RAWIP_SEND;
-               node_perm = NODE__RAWIP_SEND;
-               send_perm = 0;
-               break;
-       }
-
-       err = sel_netif_sid(ifindex, &if_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
-               return err;
-
-       err = sel_netnode_sid(addrp, family, &node_sid);
-       if (err)
-               return err;
-       err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
-       if (err)
-               return err;
-
-       if (send_perm != 0)
-               return 0;
-
-       err = sel_netport_sid(sk->sk_protocol,
-                             ntohs(ad->u.net.dport), &port_sid);
-       if (unlikely(err)) {
-               printk(KERN_WARNING
-                      "SELinux: failure in"
-                      " selinux_ip_postroute_iptables_compat(),"
-                      " network port label not found\n");
-               return err;
-       }
-       return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
-}
-
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
                                                u16 family)
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 proto;
 
@@ -4695,21 +4514,16 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
                return NF_DROP;
 
-       if (selinux_compat_net) {
-               if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
-                                                        &ad, family, addrp))
-                       return NF_DROP;
-       } else {
+       if (selinux_secmark_enabled())
                if (avc_has_perm(sksec->sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
-       }
 
        if (selinux_policycap_netpeer)
                if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
@@ -4724,7 +4538,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        u32 secmark_perm;
        u32 peer_sid;
        struct sock *sk;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4733,18 +4547,18 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         * 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_compat_net || !selinux_policycap_netpeer)
+       if (!selinux_policycap_netpeer)
                return selinux_ip_postroute_compat(skb, ifindex, family);
-
+#ifdef CONFIG_XFRM
        /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
         * packet transformation so allow the packet to pass without any checks
         * since we'll have another chance to perform access control checks
         * when the packet is on it's final way out.
         * NOTE: there appear to be some IPv6 multicast cases where skb->dst
         *       is NULL, in this case go ahead and apply access control. */
-       if (skb->dst != NULL && skb->dst->xfrm != NULL)
+       if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
                return NF_ACCEPT;
-
+#endif
        secmark_active = selinux_secmark_enabled();
        peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
        if (!secmark_active && !peerlbl_active)
@@ -4783,7 +4597,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                secmark_perm = PACKET__SEND;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
@@ -4840,26 +4654,23 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
        int err;
 
-       err = secondary_ops->netlink_send(sk, skb);
+       err = cap_netlink_send(sk, skb);
        if (err)
                return err;
 
-       if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
-               err = selinux_nlmsg_perm(sk, skb);
-
-       return err;
+       return selinux_nlmsg_perm(sk, skb);
 }
 
 static int selinux_netlink_recv(struct sk_buff *skb, int capability)
 {
        int err;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       err = secondary_ops->netlink_recv(skb, capability);
+       err = cap_netlink_recv(skb, capability);
        if (err)
                return err;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.u.cap = capability;
 
        return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
@@ -4918,12 +4729,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = ipc_perms->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = ipc_perms->key;
 
        return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
@@ -4943,7 +4754,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4953,7 +4764,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4973,12 +4784,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq)
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -5017,7 +4828,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -5038,7 +4849,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        /* Can this process write to the queue? */
@@ -5062,14 +4873,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = task_sid(target);
        int rc;
 
        isec = msq->q_perm.security;
        msec = msg->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid,
@@ -5084,7 +4895,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -5094,7 +4905,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -5114,12 +4925,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp)
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -5163,11 +4974,6 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
                             char __user *shmaddr, int shmflg)
 {
        u32 perms;
-       int rc;
-
-       rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
-       if (rc)
-               return rc;
 
        if (shmflg & SHM_RDONLY)
                perms = SHM__READ;
@@ -5181,7 +4987,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -5191,7 +4997,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5211,12 +5017,12 @@ static void selinux_sem_free_security(struct sem_array *sma)
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5434,7 +5240,7 @@ static int selinux_setprocattr(struct task_struct *p,
 
                /* Only allow single threaded processes to change context */
                error = -EPERM;
-               if (!is_single_threaded(p)) {
+               if (!current_is_single_threaded()) {
                        error = security_bounded_transition(tsec->sid, sid);
                        if (error)
                                goto abort_change;
@@ -5491,6 +5297,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
        kfree(secdata);
 }
 
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+}
+
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return __vfs_setxattr_noperm(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);
+       if (len < 0)
+               return len;
+       *ctxlen = len;
+       return 0;
+}
 #ifdef CONFIG_KEYS
 
 static int selinux_key_alloc(struct key *k, const struct cred *cred,
@@ -5562,7 +5394,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 static struct security_operations selinux_ops = {
        .name =                         "selinux",
 
-       .ptrace_may_access =            selinux_ptrace_may_access,
+       .ptrace_access_check =          selinux_ptrace_access_check,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
@@ -5577,7 +5409,6 @@ static struct security_operations selinux_ops = {
        .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_set_creds =               selinux_bprm_set_creds,
-       .bprm_check_security =          selinux_bprm_check_security,
        .bprm_committing_creds =        selinux_bprm_committing_creds,
        .bprm_committed_creds =         selinux_bprm_committed_creds,
        .bprm_secureexec =              selinux_bprm_secureexec,
@@ -5619,8 +5450,6 @@ static struct security_operations selinux_ops = {
        .inode_getsecurity =            selinux_inode_getsecurity,
        .inode_setsecurity =            selinux_inode_setsecurity,
        .inode_listsecurity =           selinux_inode_listsecurity,
-       .inode_need_killpriv =          selinux_inode_need_killpriv,
-       .inode_killpriv =               selinux_inode_killpriv,
        .inode_getsecid =               selinux_inode_getsecid,
 
        .file_permission =              selinux_file_permission,
@@ -5638,19 +5467,17 @@ static struct security_operations selinux_ops = {
        .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
+       .cred_alloc_blank =             selinux_cred_alloc_blank,
        .cred_free =                    selinux_cred_free,
        .cred_prepare =                 selinux_cred_prepare,
-       .cred_commit =                  selinux_cred_commit,
+       .cred_transfer =                selinux_cred_transfer,
        .kernel_act_as =                selinux_kernel_act_as,
        .kernel_create_files_as =       selinux_kernel_create_files_as,
-       .task_setuid =                  selinux_task_setuid,
-       .task_fix_setuid =              selinux_task_fix_setuid,
-       .task_setgid =                  selinux_task_setgid,
+       .kernel_module_request =        selinux_kernel_module_request,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
        .task_getsecid =                selinux_task_getsecid,
-       .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
        .task_setioprio =               selinux_task_setioprio,
        .task_getioprio =               selinux_task_getioprio,
@@ -5660,7 +5487,6 @@ static struct security_operations selinux_ops = {
        .task_movememory =              selinux_task_movememory,
        .task_kill =                    selinux_task_kill,
        .task_wait =                    selinux_task_wait,
-       .task_prctl =                   selinux_task_prctl,
        .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
@@ -5696,6 +5522,9 @@ static struct security_operations selinux_ops = {
        .secid_to_secctx =              selinux_secid_to_secctx,
        .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
+       .inode_notifysecctx =           selinux_inode_notifysecctx,
+       .inode_setsecctx =              selinux_inode_setsecctx,
+       .inode_getsecctx =              selinux_inode_getsecctx,
 
        .unix_stream_connect =          selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
@@ -5724,7 +5553,13 @@ static struct security_operations selinux_ops = {
        .inet_conn_request =            selinux_inet_conn_request,
        .inet_csk_clone =               selinux_inet_csk_clone,
        .inet_conn_established =        selinux_inet_conn_established,
+       .secmark_relabel_packet =       selinux_secmark_relabel_packet,
+       .secmark_refcount_inc =         selinux_secmark_refcount_inc,
+       .secmark_refcount_dec =         selinux_secmark_refcount_dec,
        .req_classify_flow =            selinux_req_classify_flow,
+       .tun_dev_create =               selinux_tun_dev_create,
+       .tun_dev_post_create =          selinux_tun_dev_post_create,
+       .tun_dev_attach =               selinux_tun_dev_attach,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
@@ -5771,14 +5606,13 @@ static __init int selinux_init(void)
        /* Set the security state for the initial task. */
        cred_init_security();
 
+       default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
+
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),
                                            0, SLAB_PANIC, NULL);
        avc_init();
 
-       secondary_ops = security_ops;
-       if (!secondary_ops)
-               panic("SELinux: No initial security operations\n");
        if (register_security(&selinux_ops))
                panic("SELinux: Unable to register with kernel.\n");
 
@@ -5790,35 +5624,18 @@ static __init int selinux_init(void)
        return 0;
 }
 
+static void delayed_superblock_init(struct super_block *sb, void *unused)
+{
+       superblock_doinit(sb, NULL);
+}
+
 void selinux_complete_init(void)
 {
        printk(KERN_DEBUG "SELinux:  Completing initialization.\n");
 
        /* Set up any superblocks initialized prior to the policy load. */
        printk(KERN_DEBUG "SELinux:  Setting up existing superblocks.\n");
-       spin_lock(&sb_lock);
-       spin_lock(&sb_security_lock);
-next_sb:
-       if (!list_empty(&superblock_security_head)) {
-               struct superblock_security_struct *sbsec =
-                               list_entry(superblock_security_head.next,
-                                          struct superblock_security_struct,
-                                          list);
-               struct super_block *sb = sbsec->sb;
-               sb->s_count++;
-               spin_unlock(&sb_security_lock);
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               if (sb->s_root)
-                       superblock_doinit(sb, NULL);
-               drop_super(sb);
-               spin_lock(&sb_lock);
-               spin_lock(&sb_security_lock);
-               list_del_init(&sbsec->list);
-               goto next_sb;
-       }
-       spin_unlock(&sb_security_lock);
-       spin_unlock(&sb_lock);
+       iterate_supers(delayed_superblock_init, NULL);
 }
 
 /* SELinux requires early initialization in order to label
@@ -5939,8 +5756,10 @@ int selinux_disable(void)
        selinux_disabled = 1;
        selinux_enabled = 0;
 
-       /* Reset security_ops to the secondary module, dummy or capability. */
-       security_ops = secondary_ops;
+       reset_security_ops();
+
+       /* Try to destroy the avc node cache */
+       avc_disable();
 
        /* Unregister netfilter hooks. */
        selinux_nf_ip_exit();