selinux: Fix packet forwarding checks on postrouting
[linux-2.6.git] / security / selinux / hooks.c
index 417f7c9..8ffed9f 100644 (file)
 #include <linux/swap.h>
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
+#include <linux/dcache.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
-#include <linux/proc_fs.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
 #include <net/ipv6.h>
 #include <linux/hugetlb.h>
 #include <linux/personality.h>
-#include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/string.h>
 #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
 
-extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 extern struct security_operations *security_ops;
 
@@ -126,18 +122,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;
 
 /**
@@ -200,7 +184,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;
 }
@@ -273,7 +257,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;
@@ -288,49 +271,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);
-
-       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",
@@ -619,10 +570,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;
@@ -813,16 +760,10 @@ 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->flags & SE_SBINITIALIZED));
@@ -1178,39 +1119,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
 }
 
 #ifdef CONFIG_PROC_FS
-static int selinux_proc_get_sid(struct proc_dir_entry *de,
+static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
 {
-       int buflen, rc;
-       char *buffer, *path, *end;
+       int rc;
+       char *buffer, *path;
 
        buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (de && de != de->parent) {
-               buflen -= de->namelen + 1;
-               if (buflen < 0)
-                       break;
-               end -= de->namelen;
-               memcpy(end, de->name, de->namelen);
-               *--end = '/';
-               path = end;
-               de = de->parent;
+       path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
+       if (IS_ERR(path))
+               rc = PTR_ERR(path);
+       else {
+               /* each process gets a /proc/PID/ entry. Strip off the
+                * PID part to get a valid selinux labeling.
+                * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+               while (path[1] >= '0' && path[1] <= '9') {
+                       path[1] = '/';
+                       path++;
+               }
+               rc = security_genfs_sid("proc", path, tclass, sid);
        }
-       rc = security_genfs_sid("proc", path, tclass, sid);
        free_page((unsigned long)buffer);
        return rc;
 }
 #else
-static int selinux_proc_get_sid(struct proc_dir_entry *de,
+static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
 {
@@ -1358,10 +1295,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
                /* Try to obtain a transition SID. */
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-               rc = security_transition_sid(isec->task_sid,
-                                            sbsec->sid,
-                                            isec->sclass,
-                                            &sid);
+               rc = security_transition_sid(isec->task_sid, sbsec->sid,
+                                            isec->sclass, NULL, &sid);
                if (rc)
                        goto out_unlock;
                isec->sid = sid;
@@ -1374,10 +1309,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                isec->sid = sbsec->sid;
 
                if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
-                       struct proc_inode *proci = PROC_I(inode);
-                       if (proci->pde) {
+                       if (opt_dentry) {
                                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-                               rc = selinux_proc_get_sid(proci->pde,
+                               rc = selinux_proc_get_sid(opt_dentry,
                                                          isec->sclass,
                                                          &sid);
                                if (rc)
@@ -1613,8 +1547,7 @@ 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;
@@ -1637,7 +1570,7 @@ static int may_create(struct inode *dir,
                return rc;
 
        if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
-               rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
+               rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid);
                if (rc)
                        return rc;
        }
@@ -1835,27 +1768,9 @@ 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 if (S_ISSOCK(mode))
-                       av |= SOCK_FILE__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;
 }
 
@@ -1939,82 +1854,6 @@ static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
        return task_has_capability(tsk, cred, cap, audit);
 }
 
-static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
-{
-       int buflen, rc;
-       char *buffer, *path, *end;
-
-       rc = -ENOMEM;
-       buffer = (char *)__get_free_page(GFP_KERNEL);
-       if (!buffer)
-               goto out;
-
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (table) {
-               const char *name = table->procname;
-               size_t namelen = strlen(name);
-               buflen -= namelen + 1;
-               if (buflen < 0)
-                       goto out_free;
-               end -= namelen;
-               memcpy(end, name, namelen);
-               *--end = '/';
-               path = end;
-               table = table->parent;
-       }
-       buflen -= 4;
-       if (buflen < 0)
-               goto out_free;
-       end -= 4;
-       memcpy(end, "/sys", 4);
-       path = end;
-       rc = security_genfs_sid("proc", path, tclass, sid);
-out_free:
-       free_page((unsigned long)buffer);
-out:
-       return rc;
-}
-
-static int selinux_sysctl(ctl_table *table, int op)
-{
-       int error = 0;
-       u32 av;
-       u32 tsid, sid;
-       int rc;
-
-       sid = current_sid();
-
-       rc = selinux_sysctl_get_sid(table, (op == 0001) ?
-                                   SECCLASS_DIR : SECCLASS_FILE, &tsid);
-       if (rc) {
-               /* Default to the well-defined sysctl SID. */
-               tsid = SECINITSID_SYSCTL;
-       }
-
-       /* The op values are "defined" in sysctl.c, thereby creating
-        * a bad coupling between this module and sysctl.c */
-       if (op == 001) {
-               error = avc_has_perm(sid, tsid,
-                                    SECCLASS_DIR, DIR__SEARCH, NULL);
-       } else {
-               av = 0;
-               if (op & 004)
-                       av |= FILE__READ;
-               if (op & 002)
-                       av |= FILE__WRITE;
-               if (av)
-                       error = avc_has_perm(sid, tsid,
-                                            SECCLASS_FILE, av, NULL);
-       }
-
-       return error;
-}
-
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
 {
        const struct cred *cred = current_cred();
@@ -2054,25 +1893,22 @@ static int selinux_syslog(int type)
 {
        int rc;
 
-       rc = cap_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;
@@ -2140,7 +1976,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(old_tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &new_tsec->sid);
+                                            SECCLASS_PROCESS, NULL,
+                                            &new_tsec->sid);
                if (rc)
                        return rc;
        }
@@ -2211,8 +2048,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *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;
 
@@ -2247,8 +2083,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.
@@ -2256,14 +2093,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. */
@@ -2361,12 +2200,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));
        }
 }
 
@@ -2411,7 +2253,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
        /* Wake up the parent if it is waiting so that it can recheck
         * wait permission to the new task SID. */
        read_lock(&tasklist_lock);
-       wake_up_interruptible(&current->real_parent->signal->wait_chldexit);
+       __wake_up_parent(current, current->real_parent);
        read_unlock(&tasklist_lock);
 }
 
@@ -2584,11 +2426,10 @@ static void selinux_inode_free_security(struct inode *inode)
 }
 
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
-                                      char **name, void **value,
-                                      size_t *len)
+                                      const struct qstr *qstr, 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;
@@ -2601,10 +2442,13 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
+       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);
+                                            qstr, &newsid);
                if (rc) {
                        printk(KERN_WARNING "%s:  "
                               "security_transition_sid failed, rc=%d (dev=%s "
@@ -2704,14 +2548,26 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
        const struct cred *cred = current_cred();
+       struct common_audit_data ad;
+       u32 perms;
+       bool from_access;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
+       from_access = mask & MAY_ACCESS;
+       mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
+
+       /* 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)
@@ -3005,13 +2861,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.
@@ -3021,7 +2879,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 */
@@ -3082,8 +2939,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
        if (selinux_checkreqprot)
                prot = reqprot;
 
-#ifndef CONFIG_PPC32
-       if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
+       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) {
@@ -3105,7 +2962,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);
 }
@@ -3335,12 +3191,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_kernel_module_request(void)
+static int selinux_kernel_module_request(char *kmod_name)
 {
-       return task_has_system(current, SYSTEM__MODULE_REQUEST);
+       u32 sid;
+       struct common_audit_data ad;
+
+       sid = task_sid(current);
+
+       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)
@@ -3390,25 +3255,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;
+       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 = cap_task_setscheduler(p, policy, lp);
+       rc = cap_task_setscheduler(p);
        if (rc)
                return rc;
 
@@ -3690,71 +3556,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 common_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;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.sk = sock->sk;
-       err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+       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;
@@ -3775,10 +3624,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;
 
@@ -3787,19 +3637,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 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);
@@ -3823,15 +3670,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                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;
@@ -3862,8 +3709,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;
        }
@@ -3874,19 +3721,18 @@ 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) {
+       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;
@@ -3909,13 +3755,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;
 
                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;
        }
@@ -3928,7 +3774,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)
@@ -3937,7 +3783,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;
 
@@ -3954,30 +3800,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)
 {
-       return socket_has_perm(current, sock, SOCKET__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;
 
@@ -3987,68 +3833,58 @@ 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,
+static int selinux_socket_unix_stream_connect(struct sock *sock,
+                                             struct sock *other,
                                              struct sock *newsk)
 {
-       struct sk_security_struct *ssec;
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
+       struct sk_security_struct *sksec_sock = sock->sk_security;
+       struct sk_security_struct *sksec_other = other->sk_security;
+       struct sk_security_struct *sksec_new = newsk->sk_security;
        struct common_audit_data ad;
        int err;
 
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
-
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.sk = other->sk;
+       ad.u.net.sk = other;
 
-       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 sk_security_struct *ssec = sock->sk->sk_security;
+       struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
-       int err;
-
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
 
        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,
@@ -4079,13 +3915,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 {
        int err = 0;
        struct sk_security_struct *sksec = sk->sk_security;
-       u32 peer_sid;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
        char *addrp;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
@@ -4098,20 +3933,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                        return err;
        }
 
-       if (selinux_policycap_netpeer) {
-               err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
-               if (err)
-                       return err;
-               err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, &ad);
-               if (err)
-                       selinux_netlbl_err(skb, err, 0);
-       } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
-               if (err)
-                       return err;
-               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
-       }
+       err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
+       if (err)
+               return err;
+       err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
 
        return err;
 }
@@ -4147,7 +3972,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                return 0;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
@@ -4159,7 +3984,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);
@@ -4187,26 +4012,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;
@@ -4219,9 +4036,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;
 }
 
@@ -4253,24 +4068,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);
+       selinux_netlbl_sk_security_reset(newsksec);
 }
 
 static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4354,6 +4184,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
        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);
+}
+
+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,
                                      struct flowi *fl)
 {
@@ -4418,8 +4269,7 @@ 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;
@@ -4427,13 +4277,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;
                }
@@ -4444,7 +4294,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;
 }
@@ -4579,11 +4429,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        if (selinux_secmark_enabled())
                if (avc_has_perm(sksec->sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
-                       return NF_DROP;
+                       return NF_DROP_ERR(-ECONNREFUSED);
 
-       if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
-                       return NF_DROP;
+       if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
+               return NF_DROP_ERR(-ECONNREFUSED);
 
        return NF_ACCEPT;
 }
@@ -4626,27 +4475,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
        if (sk == NULL) {
-               switch (family) {
-               case PF_INET:
-                       if (IPCB(skb)->flags & IPSKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               case PF_INET6:
-                       if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               default:
-                       return NF_DROP;
-               }
-               if (secmark_perm == PACKET__FORWARD_OUT) {
+               if (skb->skb_iif) {
+                       secmark_perm = PACKET__FORWARD_OUT;
                        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
                                return NF_DROP;
-               } else
+               } else {
+                       secmark_perm = PACKET__SEND;
                        peer_sid = SECINITSID_KERNEL;
+               }
        } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
@@ -4662,7 +4498,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, secmark_perm, &ad))
-                       return NF_DROP;
+                       return NF_DROP_ERR(-ECONNREFUSED);
 
        if (peerlbl_active) {
                u32 if_sid;
@@ -4672,13 +4508,13 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                        return NF_DROP;
                if (avc_has_perm(peer_sid, if_sid,
                                 SECCLASS_NETIF, NETIF__EGRESS, &ad))
-                       return NF_DROP;
+                       return NF_DROP_ERR(-ECONNREFUSED);
 
                if (sel_netnode_sid(addrp, family, &node_sid))
                        return NF_DROP;
                if (avc_has_perm(peer_sid, node_sid,
                                 SECCLASS_NODE, NODE__SENDTO, &ad))
-                       return NF_DROP;
+                       return NF_DROP_ERR(-ECONNREFUSED);
        }
 
        return NF_ACCEPT;
@@ -4714,10 +4550,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *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)
@@ -4903,7 +4736,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                 * message queue this message will be stored in
                 */
                rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
-                                            &msec->sid);
+                                            NULL, &msec->sid);
                if (rc)
                        return rc;
        }
@@ -5457,7 +5290,6 @@ static struct security_operations selinux_ops = {
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
-       .sysctl =                       selinux_sysctl,
        .capable =                      selinux_capable,
        .quotactl =                     selinux_quotactl,
        .quota_on =                     selinux_quota_on,
@@ -5612,6 +5444,9 @@ 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,
@@ -5662,14 +5497,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");
 
@@ -5681,35 +5515,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
@@ -5830,12 +5647,11 @@ int selinux_disable(void)
        selinux_disabled = 1;
        selinux_enabled = 0;
 
+       reset_security_ops();
+
        /* Try to destroy the avc node cache */
        avc_disable();
 
-       /* Reset security_ops to the secondary module, dummy or capability. */
-       security_ops = secondary_ops;
-
        /* Unregister netfilter hooks. */
        selinux_nf_ip_exit();