net: reduce structures when XFRM=n
[safe/jmp/linux-2.6] / security / selinux / hooks.c
index 4bf4807..aedf02b 100644 (file)
@@ -4,27 +4,28 @@
  *  This file contains the SELinux hook function implementations.
  *
  *  Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
- *            Chris Vance, <cvance@nai.com>
- *            Wayne Salamon, <wsalamon@nai.com>
- *            James Morris <jmorris@redhat.com>
+ *           Chris Vance, <cvance@nai.com>
+ *           Wayne Salamon, <wsalamon@nai.com>
+ *           James Morris <jmorris@redhat.com>
  *
  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
- *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *                                        Eric Paris <eparis@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
- *                          <dgoeddel@trustedcs.com>
+ *                         <dgoeddel@trustedcs.com>
  *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
- *                Paul Moore <paul.moore@hp.com>
+ *             Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
- *                     Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2,
- *      as published by the Free Software Foundation.
+ *     as published by the Free Software Foundation.
  */
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/security.h>
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
-#include <linux/kd.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
@@ -52,7 +52,7 @@
 #include <net/tcp.h>           /* struct or_callable used in sock_rcv_skb */
 #include <net/net_namespace.h>
 #include <net/netlabel.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
 #include <linux/selinux.h>
 #include <linux/mutex.h>
+#include <linux/posix-timers.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "netif.h"
 #include "netnode.h"
+#include "netport.h"
 #include "xfrm.h"
 #include "netlabel.h"
+#include "audit.h"
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -97,11 +100,13 @@ extern struct security_operations *security_ops;
 atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
-int selinux_enforcing = 0;
+int selinux_enforcing;
 
 static int __init enforcing_setup(char *str)
 {
-       selinux_enforcing = simple_strtol(str,NULL,0);
+       unsigned long enforcing;
+       if (!strict_strtoul(str, 0, &enforcing))
+               selinux_enforcing = enforcing ? 1 : 0;
        return 1;
 }
 __setup("enforcing=", enforcing_setup);
@@ -112,7 +117,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
 
 static int __init selinux_enabled_setup(char *str)
 {
-       selinux_enabled = simple_strtol(str, NULL, 0);
+       unsigned long enabled;
+       if (!strict_strtoul(str, 0, &enabled))
+               selinux_enabled = enabled ? 1 : 0;
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
@@ -120,14 +127,12 @@ __setup("selinux=", selinux_enabled_setup);
 int selinux_enabled = 1;
 #endif
 
-/* Original (dummy) security module. */
-static struct security_operations *original_ops = NULL;
 
-/* Minimal support for a secondary security module,
-   just to allow the use of the dummy or capability modules.
-   The owlsm module can alternatively be used as a secondary
  module as long as CONFIG_OWLSM_FD is not enabled. */
-static struct security_operations *secondary_ops = NULL;
+/*
+ * 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. */
@@ -161,8 +166,7 @@ static int task_alloc_security(struct task_struct *task)
        if (!tsec)
                return -ENOMEM;
 
-       tsec->task = task;
-       tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
+       tsec->osid = tsec->sid = SECINITSID_UNLABELED;
        task->security = tsec;
 
        return 0;
@@ -180,7 +184,7 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kmem_cache_zalloc(sel_inode_cache, GFP_KERNEL);
+       isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
        if (!isec)
                return -ENOMEM;
 
@@ -218,7 +222,6 @@ static int file_alloc_security(struct file *file)
        if (!fsec)
                return -ENOMEM;
 
-       fsec->file = file;
        fsec->sid = tsec->sid;
        fsec->fown_sid = tsec->sid;
        file->f_security = fsec;
@@ -275,12 +278,11 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
        if (!ssec)
                return -ENOMEM;
 
-       ssec->sk = sk;
        ssec->peer_sid = SECINITSID_UNLABELED;
        ssec->sid = SECINITSID_UNLABELED;
        sk->sk_security = ssec;
 
-       selinux_netlbl_sk_security_init(ssec, family);
+       selinux_netlbl_sk_security_reset(ssec, family);
 
        return 0;
 }
@@ -290,6 +292,7 @@ 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);
 }
 
@@ -323,11 +326,11 @@ enum {
        Opt_rootcontext = 4,
 };
 
-static match_table_t tokens = {
-       {Opt_context, "context=%s"},
-       {Opt_fscontext, "fscontext=%s"},
-       {Opt_defcontext, "defcontext=%s"},
-       {Opt_rootcontext, "rootcontext=%s"},
+static const match_table_t tokens = {
+       {Opt_context, CONTEXT_STR "%s"},
+       {Opt_fscontext, FSCONTEXT_STR "%s"},
+       {Opt_defcontext, DEFCONTEXT_STR "%s"},
+       {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
        {Opt_error, NULL},
 };
 
@@ -576,8 +579,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                        goto out;
                }
                rc = -EINVAL;
-               printk(KERN_WARNING "Unable to set superblock options before "
-                      "the security server is initialized\n");
+               printk(KERN_WARNING "SELinux: Unable to set superblock options "
+                       "before the security server is initialized\n");
                goto out;
        }
 
@@ -594,7 +597,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
            && (num_opts == 0))
-               goto out;
+               goto out;
 
        /*
         * parse the mount options, check if they are valid sids.
@@ -671,7 +674,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
-                      __FUNCTION__, sb->s_type->name, rc);
+                      __func__, sb->s_type->name, rc);
                goto out;
        }
 
@@ -756,17 +759,26 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        int set_context =       (oldsbsec->flags & CONTEXT_MNT);
        int set_rootcontext =   (oldsbsec->flags & ROOTCONTEXT_MNT);
 
-       /* we can't error, we can't save the info, this shouldn't get called
-        * this early in the boot process. */
-       BUG_ON(!ss_initialized);
-
-       /* this might go away sometime down the line if there is a new user
-        * of clone, but for now, nfs better not get here... */
-       BUG_ON(newsbsec->initialized);
+       /*
+        * 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
+        */
+       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);
+               return;
+       }
 
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!oldsbsec->initialized);
 
+       /* if fs is reusing a sb, just let its options stand... */
+       if (newsbsec->initialized)
+               return;
+
        mutex_lock(&newsbsec->lock);
 
        newsbsec->flags = oldsbsec->flags;
@@ -800,7 +812,8 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        mutex_unlock(&newsbsec->lock);
 }
 
-int selinux_parse_opts_str(char *options, struct security_mnt_opts *opts)
+static int selinux_parse_opts_str(char *options,
+                                 struct security_mnt_opts *opts)
 {
        char *p;
        char *context = NULL, *defcontext = NULL;
@@ -946,6 +959,62 @@ out_err:
        return rc;
 }
 
+static void selinux_write_opts(struct seq_file *m,
+                              struct security_mnt_opts *opts)
+{
+       int i;
+       char *prefix;
+
+       for (i = 0; i < opts->num_mnt_opts; i++) {
+               char *has_comma = strchr(opts->mnt_opts[i], ',');
+
+               switch (opts->mnt_opts_flags[i]) {
+               case CONTEXT_MNT:
+                       prefix = CONTEXT_STR;
+                       break;
+               case FSCONTEXT_MNT:
+                       prefix = FSCONTEXT_STR;
+                       break;
+               case ROOTCONTEXT_MNT:
+                       prefix = ROOTCONTEXT_STR;
+                       break;
+               case DEFCONTEXT_MNT:
+                       prefix = DEFCONTEXT_STR;
+                       break;
+               default:
+                       BUG();
+               };
+               /* we need a comma before each option */
+               seq_putc(m, ',');
+               seq_puts(m, prefix);
+               if (has_comma)
+                       seq_putc(m, '\"');
+               seq_puts(m, opts->mnt_opts[i]);
+               if (has_comma)
+                       seq_putc(m, '\"');
+       }
+}
+
+static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
+{
+       struct security_mnt_opts opts;
+       int rc;
+
+       rc = selinux_get_mnt_opts(sb, &opts);
+       if (rc) {
+               /* before policy load we may get EINVAL, don't show anything */
+               if (rc == -EINVAL)
+                       rc = 0;
+               return rc;
+       }
+
+       selinux_write_opts(m, &opts);
+
+       security_free_mnt_opts(&opts);
+
+       return rc;
+}
+
 static inline u16 inode_mode_to_security_class(umode_t mode)
 {
        switch (mode & S_IFMT) {
@@ -1054,7 +1123,7 @@ static int selinux_proc_get_sid(struct proc_dir_entry *de,
        int buflen, rc;
        char *buffer, *path, *end;
 
-       buffer = (char*)__get_free_page(GFP_KERNEL);
+       buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
@@ -1135,14 +1204,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        dentry = d_find_alias(inode);
                }
                if (!dentry) {
-                       printk(KERN_WARNING "%s:  no dentry for dev=%s "
-                              "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
+                       printk(KERN_WARNING "SELinux: %s:  no dentry for dev=%s "
+                              "ino=%ld\n", __func__, inode->i_sb->s_id,
                               inode->i_ino);
                        goto out_unlock;
                }
 
                len = INITCONTEXTLEN;
-               context = kmalloc(len, GFP_KERNEL);
+               context = kmalloc(len, GFP_NOFS);
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
@@ -1160,7 +1229,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        }
                        kfree(context);
                        len = rc;
-                       context = kmalloc(len, GFP_KERNEL);
+                       context = kmalloc(len, GFP_NOFS);
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
@@ -1173,8 +1242,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                dput(dentry);
                if (rc < 0) {
                        if (rc != -ENODATA) {
-                               printk(KERN_WARNING "%s:  getxattr returned "
-                                      "%d for dev=%s ino=%ld\n", __FUNCTION__,
+                               printk(KERN_WARNING "SELinux: %s:  getxattr returned "
+                                      "%d for dev=%s ino=%ld\n", __func__,
                                       -rc, inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
                                goto out_unlock;
@@ -1184,11 +1253,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        rc = 0;
                } else {
                        rc = security_context_to_sid_default(context, rc, &sid,
-                                                            sbsec->def_sid);
+                                                            sbsec->def_sid,
+                                                            GFP_NOFS);
                        if (rc) {
-                               printk(KERN_WARNING "%s:  context_to_sid(%s) "
+                               printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
                                       "returned %d for dev=%s ino=%ld\n",
-                                      __FUNCTION__, context, -rc,
+                                      __func__, context, -rc,
                                       inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
                                /* Leave with the unlabeled SID */
@@ -1223,7 +1293,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) {
+               if (sbsec->proc && !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);
@@ -1304,7 +1374,7 @@ static int task_has_capability(struct task_struct *tsk,
 
        tsec = tsk->security;
 
-       AVC_AUDIT_DATA_INIT(&ad,CAP);
+       AVC_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
@@ -1347,7 +1417,7 @@ static int inode_has_perm(struct task_struct *tsk,
        struct inode_security_struct *isec;
        struct avc_audit_data ad;
 
-       if (unlikely (IS_PRIVATE (inode)))
+       if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
        tsec = tsk->security;
@@ -1372,7 +1442,7 @@ static inline int dentry_has_perm(struct task_struct *tsk,
 {
        struct inode *inode = dentry->d_inode;
        struct avc_audit_data ad;
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
        return inode_has_perm(tsk, inode, av, &ad);
@@ -1469,9 +1539,9 @@ static int may_create_key(u32 ksid,
        return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
 }
 
-#define MAY_LINK   0
-#define MAY_UNLINK 1
-#define MAY_RMDIR  2
+#define MAY_LINK       0
+#define MAY_UNLINK     1
+#define MAY_RMDIR      2
 
 /* Check whether a task can link, unlink, or rmdir a file/directory. */
 static int may_link(struct inode *dir,
@@ -1509,7 +1579,8 @@ static int may_link(struct inode *dir,
                av = DIR__RMDIR;
                break;
        default:
-               printk(KERN_WARNING "may_link:  unrecognized kind %d\n", kind);
+               printk(KERN_WARNING "SELinux: %s:  unrecognized kind %d\n",
+                       __func__, kind);
                return 0;
        }
 
@@ -1616,6 +1687,35 @@ static inline u32 file_mask_to_av(int mode, int mask)
        return av;
 }
 
+/*
+ * Convert a file mask to an access vector and include the correct open
+ * open permission.
+ */
+static inline u32 open_file_mask_to_av(int mode, int mask)
+{
+       u32 av = file_mask_to_av(mode, mask);
+
+       if (selinux_policycap_openperm) {
+               /*
+                * 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:%x\n", __func__, mode);
+       }
+       return av;
+}
+
 /* Convert a Linux file to an access vector. */
 static inline u32 file_to_av(struct file *file)
 {
@@ -1629,31 +1729,50 @@ static inline u32 file_to_av(struct file *file)
                else
                        av |= FILE__WRITE;
        }
+       if (!av) {
+               /*
+                * Special file opened with flags 3 for ioctl-only use.
+                */
+               av = FILE__IOCTL;
+       }
 
        return av;
 }
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
+static int selinux_ptrace_may_access(struct task_struct *child,
+                                    unsigned int mode)
 {
-       struct task_security_struct *psec = parent->security;
-       struct task_security_struct *csec = child->security;
        int rc;
 
-       rc = secondary_ops->ptrace(parent,child);
+       rc = secondary_ops->ptrace_may_access(child, mode);
        if (rc)
                return rc;
 
-       rc = task_has_perm(parent, child, PROCESS__PTRACE);
-       /* Save the SID of the tracing process for later use in apply_creds. */
-       if (!(child->ptrace & PT_PTRACED) && !rc)
-               csec->ptrace_sid = psec->sid;
-       return rc;
+       if (mode == PTRACE_MODE_READ) {
+               struct task_security_struct *tsec = current->security;
+               struct task_security_struct *csec = child->security;
+               return avc_has_perm(tsec->sid, csec->sid,
+                                   SECCLASS_FILE, FILE__READ, NULL);
+       }
+
+       return task_has_perm(current, child, PROCESS__PTRACE);
+}
+
+static int selinux_ptrace_traceme(struct task_struct *parent)
+{
+       int rc;
+
+       rc = secondary_ops->ptrace_traceme(parent);
+       if (rc)
+               return rc;
+
+       return task_has_perm(parent, current, PROCESS__PTRACE);
 }
 
 static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
-                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                         kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        int error;
 
@@ -1665,7 +1784,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
 }
 
 static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
-                                kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        int error;
 
@@ -1677,7 +1796,7 @@ static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effect
 }
 
 static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
-                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                              kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        secondary_ops->capset_set(target, effective, inheritable, permitted);
 }
@@ -1690,7 +1809,7 @@ static int selinux_capable(struct task_struct *tsk, int cap)
        if (rc)
                return rc;
 
-       return task_has_capability(tsk,cap);
+       return task_has_capability(tsk, cap);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -1699,7 +1818,7 @@ static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
        char *buffer, *path, *end;
 
        rc = -ENOMEM;
-       buffer = (char*)__get_free_page(GFP_KERNEL);
+       buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                goto out;
 
@@ -1757,7 +1876,7 @@ static int selinux_sysctl(ctl_table *table, int op)
 
        /* The op values are "defined" in sysctl.c, thereby creating
         * a bad coupling between this module and sysctl.c */
-       if(op == 001) {
+       if (op == 001) {
                error = avc_has_perm(tsec->sid, tsid,
                                     SECCLASS_DIR, DIR__SEARCH, NULL);
        } else {
@@ -1769,7 +1888,7 @@ static int selinux_sysctl(ctl_table *table, int op)
                if (av)
                        error = avc_has_perm(tsec->sid, tsid,
                                             SECCLASS_FILE, av, NULL);
-        }
+       }
 
        return error;
 }
@@ -1782,25 +1901,23 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
                return 0;
 
        switch (cmds) {
-               case Q_SYNC:
-               case Q_QUOTAON:
-               case Q_QUOTAOFF:
-               case Q_SETINFO:
-               case Q_SETQUOTA:
-                       rc = superblock_has_perm(current,
-                                                sb,
-                                                FILESYSTEM__QUOTAMOD, NULL);
-                       break;
-               case Q_GETFMT:
-               case Q_GETINFO:
-               case Q_GETQUOTA:
-                       rc = superblock_has_perm(current,
-                                                sb,
-                                                FILESYSTEM__QUOTAGET, NULL);
-                       break;
-               default:
-                       rc = 0;  /* let the kernel handle invalid cmds */
-                       break;
+       case Q_SYNC:
+       case Q_QUOTAON:
+       case Q_QUOTAOFF:
+       case Q_SETINFO:
+       case Q_SETQUOTA:
+               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
+                                        NULL);
+               break;
+       case Q_GETFMT:
+       case Q_GETINFO:
+       case Q_GETQUOTA:
+               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
+                                        NULL);
+               break;
+       default:
+               rc = 0;  /* let the kernel handle invalid cmds */
+               break;
        }
        return rc;
 }
@@ -1819,23 +1936,23 @@ static int selinux_syslog(int type)
                return rc;
 
        switch (type) {
-               case 3:         /* Read last kernel messages */
-               case 10:        /* 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 */
-                       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 */
-               default:
-                       rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
-                       break;
+       case 3:         /* Read last kernel messages */
+       case 10:        /* 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 */
+               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 */
+       default:
+               rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
+               break;
        }
        return rc;
 }
@@ -1881,7 +1998,6 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
        if (!bsec)
                return -ENOMEM;
 
-       bsec->bprm = bprm;
        bsec->sid = SECINITSID_UNLABELED;
        bsec->set = 0;
 
@@ -1926,7 +2042,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &newsid);
+                                            SECCLASS_PROCESS, &newsid);
                if (rc)
                        return rc;
        }
@@ -1937,7 +2053,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                newsid = tsec->sid;
 
-        if (tsec->sid == newsid) {
+       if (tsec->sid == newsid) {
                rc = avc_has_perm(tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
                if (rc)
@@ -1965,13 +2081,13 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        return 0;
 }
 
-static int selinux_bprm_check_security (struct linux_binprm *bprm)
+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)
+static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
        struct task_security_struct *tsec = current->security;
        int atsecure = 0;
@@ -1998,7 +2114,7 @@ extern struct vfsmount *selinuxfs_mount;
 extern struct dentry *selinux_null;
 
 /* Derived from fs/exec.c:flush_old_files. */
-static inline void flush_unauthorized_files(struct files_struct * files)
+static inline void flush_unauthorized_files(struct files_struct *files)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
@@ -2007,7 +2123,6 @@ static inline void flush_unauthorized_files(struct files_struct * files)
        long j = -1;
        int drop_tty = 0;
 
-       mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
                file_list_lock();
@@ -2025,15 +2140,15 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                        }
                }
                file_list_unlock();
+               tty_kref_put(tty);
        }
-       mutex_unlock(&tty_mutex);
        /* Reset controlling tty. */
        if (drop_tty)
                no_tty();
 
        /* Revalidate access to inherited open files. */
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2049,7 +2164,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                if (!set)
                        continue;
                spin_unlock(&files->file_lock);
-               for ( ; set ; i++,set >>= 1) {
+               for ( ; set ; i++, set >>= 1) {
                        if (set & 1) {
                                file = fget(i);
                                if (!file)
@@ -2118,12 +2233,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and kill. */
                if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-                       rc = avc_has_perm(tsec->ptrace_sid, sid,
-                                         SECCLASS_PROCESS, PROCESS__PTRACE,
-                                         NULL);
-                       if (rc) {
-                               bsec->unsafe = 1;
-                               return;
+                       struct task_struct *tracer;
+                       struct task_security_struct *sec;
+                       u32 ptsid = 0;
+
+                       rcu_read_lock();
+                       tracer = tracehook_tracer_task(current);
+                       if (likely(tracer != NULL)) {
+                               sec = tracer->security;
+                               ptsid = sec->sid;
+                       }
+                       rcu_read_unlock();
+
+                       if (ptsid != 0) {
+                               rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+                                                 PROCESS__PTRACE, NULL);
+                               if (rc) {
+                                       bsec->unsafe = 1;
+                                       return;
+                               }
                        }
                }
                tsec->sid = sid;
@@ -2193,15 +2321,9 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
                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);
-               }
-               if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
-                       /*
-                        * This will cause RLIMIT_CPU calculations
-                        * to be refigured.
-                        */
-                       current->it_prof_expires = jiffies_to_cputime(1);
+                       rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
                }
+               update_rlimit_cpu(rlim->rlim_cur);
        }
 
        /* Wake up the parent if it is waiting so that it can
@@ -2231,10 +2353,10 @@ static inline int match_prefix(char *prefix, int plen, char *option, int olen)
 
 static inline int selinux_option(char *option, int len)
 {
-       return (match_prefix("context=", sizeof("context=")-1, option, len) ||
-               match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) ||
-               match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) ||
-               match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, 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));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -2248,16 +2370,15 @@ static inline void take_option(char **to, char *from, int *first, int len)
        *to += len;
 }
 
-static inline void take_selinux_option(char **to, char *from, int *first, 
-                                      int len)
+static inline void take_selinux_option(char **to, char *from, int *first,
+                                      int len)
 {
        int current_size = 0;
 
        if (!*first) {
                **to = '|';
                *to += 1;
-       }
-       else
+       } else
                *first = 0;
 
        while (current_size < len) {
@@ -2321,7 +2442,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
        if (rc)
                return rc;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
        return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2330,29 +2451,29 @@ static int selinux_sb_statfs(struct dentry *dentry)
 {
        struct avc_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
-static int selinux_mount(char * dev_name,
-                         struct nameidata *nd,
-                         char * type,
-                         unsigned long flags,
-                         void * data)
+static int selinux_mount(char *dev_name,
+                        struct path *path,
+                        char *type,
+                        unsigned long flags,
+                        void *data)
 {
        int rc;
 
-       rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);
+       rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
        if (rc)
                return rc;
 
        if (flags & MS_REMOUNT)
-               return superblock_has_perm(current, nd->path.mnt->mnt_sb,
-                                          FILESYSTEM__REMOUNT, NULL);
+               return superblock_has_perm(current, path->mnt->mnt_sb,
+                                          FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(current, nd->path.mnt, nd->path.dentry,
-                                      FILE__MOUNTON);
+               return dentry_has_perm(current, path->mnt, path->dentry,
+                                      FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2363,8 +2484,8 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
        if (rc)
                return rc;
 
-       return superblock_has_perm(current,mnt->mnt_sb,
-                                  FILESYSTEM__UNMOUNT,NULL);
+       return superblock_has_perm(current, mnt->mnt_sb,
+                                  FILESYSTEM__UNMOUNT, NULL);
 }
 
 /* inode security operations */
@@ -2404,7 +2525,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                        printk(KERN_WARNING "%s:  "
                               "security_transition_sid failed, rc=%d (dev=%s "
                               "ino=%ld)\n",
-                              __FUNCTION__,
+                              __func__,
                               -rc, inode->i_sb->s_id, inode->i_ino);
                        return rc;
                }
@@ -2422,14 +2543,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                return -EOPNOTSUPP;
 
        if (name) {
-               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
+               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
                if (!namep)
                        return -ENOMEM;
                *name = namep;
        }
 
        if (value && len) {
-               rc = security_sid_to_context(newsid, &context, &clen);
+               rc = security_sid_to_context_force(newsid, &context, &clen);
                if (rc) {
                        kfree(namep);
                        return rc;
@@ -2450,7 +2571,7 @@ static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, stru
 {
        int rc;
 
-       rc = secondary_ops->inode_link(old_dentry,dir,new_dentry);
+       rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
        if (rc)
                return rc;
        return may_link(dir, old_dentry, MAY_LINK);
@@ -2493,7 +2614,7 @@ static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mod
 }
 
 static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
-                                struct inode *new_inode, struct dentry *new_dentry)
+                               struct inode *new_inode, struct dentry *new_dentry)
 {
        return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }
@@ -2507,18 +2628,17 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 {
        int rc;
 
-       rc = secondary_ops->inode_follow_link(dentry,nameidata);
+       rc = secondary_ops->inode_follow_link(dentry, nameidata);
        if (rc)
                return rc;
        return dentry_has_perm(current, NULL, dentry, FILE__READ);
 }
 
-static int selinux_inode_permission(struct inode *inode, int mask,
-                                   struct nameidata *nd)
+static int selinux_inode_permission(struct inode *inode, int mask)
 {
        int rc;
 
-       rc = secondary_ops->inode_permission(inode, mask, nd);
+       rc = secondary_ops->inode_permission(inode, mask);
        if (rc)
                return rc;
 
@@ -2528,7 +2648,7 @@ static int selinux_inode_permission(struct inode *inode, int mask,
        }
 
        return inode_has_perm(current, inode,
-                              file_mask_to_av(inode->i_mode, mask), NULL);
+                              open_file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2554,7 +2674,7 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
        return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_setotherxattr(struct dentry *dentry, char *name)
+static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 {
        if (!strncmp(name, XATTR_SECURITY_PREFIX,
                     sizeof XATTR_SECURITY_PREFIX - 1)) {
@@ -2573,7 +2693,8 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, char *name)
        return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
 }
 
-static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
+static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
+                                 const void *value, size_t size, int flags)
 {
        struct task_security_struct *tsec = current->security;
        struct inode *inode = dentry->d_inode;
@@ -2593,7 +2714,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
        if (!is_owner_or_cap(inode))
                return -EPERM;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
@@ -2602,6 +2723,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                return rc;
 
        rc = security_context_to_sid(value, size, &newsid);
+       if (rc == -EINVAL) {
+               if (!capable(CAP_MAC_ADMIN))
+                       return rc;
+               rc = security_context_to_sid_force(value, size, &newsid);
+       }
        if (rc)
                return rc;
 
@@ -2611,7 +2737,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                return rc;
 
        rc = security_validate_transition(isec->sid, newsid, tsec->sid,
-                                         isec->sclass);
+                                         isec->sclass);
        if (rc)
                return rc;
 
@@ -2622,8 +2748,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                            &ad);
 }
 
-static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
-                                        void *value, size_t size, int flags)
+static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
+                                       const void *value, size_t size,
+                                       int flags)
 {
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
@@ -2635,10 +2762,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
                return;
        }
 
-       rc = security_context_to_sid(value, size, &newsid);
+       rc = security_context_to_sid_force(value, size, &newsid);
        if (rc) {
-               printk(KERN_WARNING "%s:  unable to obtain SID for context "
-                      "%s, rc=%d\n", __FUNCTION__, (char*)value, -rc);
+               printk(KERN_ERR "SELinux:  unable to map context to SID"
+                      "for (%s, %lu), rc=%d\n",
+                      inode->i_sb->s_id, inode->i_ino, -rc);
                return;
        }
 
@@ -2646,17 +2774,17 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
        return;
 }
 
-static int selinux_inode_getxattr (struct dentry *dentry, char *name)
+static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_listxattr (struct dentry *dentry)
+static int selinux_inode_listxattr(struct dentry *dentry)
 {
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_removexattr (struct dentry *dentry, char *name)
+static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
 {
        if (strcmp(name, XATTR_NAME_SELINUX))
                return selinux_inode_setotherxattr(dentry, name);
@@ -2667,9 +2795,7 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
 }
 
 /*
- * Copy the in-core inode security context value to the user.  If the
- * getxattr() prior to this succeeded, check to see if we need to
- * canonicalize the value to be finally returned to the user.
+ * Copy the inode security context value to the user.
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
@@ -2678,12 +2804,33 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
        u32 size;
        int error;
        char *context = NULL;
+       struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
-       error = security_sid_to_context(isec->sid, &context, &size);
+       /*
+        * If the caller has CAP_MAC_ADMIN, then get the raw context
+        * value even if it is not defined by current policy; otherwise,
+        * use the in-core value under current policy.
+        * Use the non-auditing forms of the permission checks since
+        * getxattr may be called by unprivileged processes commonly
+        * and lack of permission just means that we fall back to the
+        * in-core context value, not a denial.
+        */
+       error = secondary_ops->capable(current, CAP_MAC_ADMIN);
+       if (!error)
+               error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+                                            SECCLASS_CAPABILITY2,
+                                            CAPABILITY2__MAC_ADMIN,
+                                            0,
+                                            NULL);
+       if (!error)
+               error = security_sid_to_context_force(isec->sid, &context,
+                                                     &size);
+       else
+               error = security_sid_to_context(isec->sid, &context, &size);
        if (error)
                return error;
        error = size;
@@ -2697,7 +2844,7 @@ out_nofree:
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
-                                     const void *value, size_t size, int flags)
+                                    const void *value, size_t size, int flags)
 {
        struct inode_security_struct *isec = inode->i_security;
        u32 newsid;
@@ -2709,7 +2856,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid((void*)value, size, &newsid);
+       rc = security_context_to_sid((void *)value, size, &newsid);
        if (rc)
                return rc;
 
@@ -2735,6 +2882,12 @@ 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;
+       *secid = isec->sid;
+}
+
 /* file security operations */
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -2791,47 +2944,16 @@ static void selinux_file_free_security(struct file *file)
 static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
-       int error = 0;
-
-       switch (cmd) {
-               case FIONREAD:
-               /* fall through */
-               case FIBMAP:
-               /* fall through */
-               case FIGETBSZ:
-               /* fall through */
-               case EXT2_IOC_GETFLAGS:
-               /* fall through */
-               case EXT2_IOC_GETVERSION:
-                       error = file_has_perm(current, file, FILE__GETATTR);
-                       break;
-
-               case EXT2_IOC_SETFLAGS:
-               /* fall through */
-               case EXT2_IOC_SETVERSION:
-                       error = file_has_perm(current, file, FILE__SETATTR);
-                       break;
-
-               /* sys_ioctl() checks */
-               case FIONBIO:
-               /* fall through */
-               case FIOASYNC:
-                       error = file_has_perm(current, file, 0);
-                       break;
-
-               case KDSKBENT:
-               case KDSKBSENT:
-                       error = task_has_capability(current,CAP_SYS_TTY_CONFIG);
-                       break;
+       u32 av = 0;
 
-               /* default case assumes that the command will go
-                * to the file's ioctl() function.
-                */
-               default:
-                       error = file_has_perm(current, file, FILE__IOCTL);
+       if (_IOC_DIR(cmd) & _IOC_WRITE)
+               av |= FILE__WRITE;
+       if (_IOC_DIR(cmd) & _IOC_READ)
+               av |= FILE__READ;
+       if (!av)
+               av = FILE__IOCTL;
 
-       }
-       return error;
+       return file_has_perm(current, file, av);
 }
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
@@ -2870,7 +2992,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
                             unsigned long addr, unsigned long addr_only)
 {
        int rc = 0;
-       u32 sid = ((struct task_security_struct*)(current->security))->sid;
+       u32 sid = ((struct task_security_struct *)(current->security))->sid;
 
        if (addr < mmap_min_addr)
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -2939,39 +3061,39 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
        int err = 0;
 
        switch (cmd) {
-               case F_SETFL:
-                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
-                               err = -EINVAL;
-                               break;
-                       }
+       case F_SETFL:
+               if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
+                       err = -EINVAL;
+                       break;
+               }
 
-                       if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
-                               err = file_has_perm(current, file,FILE__WRITE);
-                               break;
-                       }
-                       /* fall through */
-               case F_SETOWN:
-               case F_SETSIG:
-               case F_GETFL:
-               case F_GETOWN:
-               case F_GETSIG:
-                       /* Just check FD__USE permission */
-                       err = file_has_perm(current, file, 0);
+               if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
+                       err = file_has_perm(current, file, FILE__WRITE);
                        break;
-               case F_GETLK:
-               case F_SETLK:
-               case F_SETLKW:
+               }
+               /* fall through */
+       case F_SETOWN:
+       case F_SETSIG:
+       case F_GETFL:
+       case F_GETOWN:
+       case F_GETSIG:
+               /* Just check FD__USE permission */
+               err = file_has_perm(current, file, 0);
+               break;
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
 #if BITS_PER_LONG == 32
-               case F_GETLK64:
-               case F_SETLK64:
-               case F_SETLKW64:
+       case F_GETLK64:
+       case F_SETLK64:
+       case F_SETLKW64:
 #endif
-                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
-                               err = -EINVAL;
-                               break;
-                       }
-                       err = file_has_perm(current, file, FILE__LOCK);
+               if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
+                       err = -EINVAL;
                        break;
+               }
+               err = file_has_perm(current, file, FILE__LOCK);
+               break;
        }
 
        return err;
@@ -2992,13 +3114,13 @@ static int selinux_file_set_fowner(struct file *file)
 static int selinux_file_send_sigiotask(struct task_struct *tsk,
                                       struct fown_struct *fown, int signum)
 {
-        struct file *file;
+       struct file *file;
        u32 perm;
        struct task_security_struct *tsec;
        struct file_security_struct *fsec;
 
        /* struct fown_struct is never outside the context of a struct file */
-        file = container_of(fown, struct file, f_owner);
+       file = container_of(fown, struct file, f_owner);
 
        tsec = tsk->security;
        fsec = file->f_security;
@@ -3079,11 +3201,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->keycreate_sid = tsec1->keycreate_sid;
        tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
-       /* Retain ptracer SID across fork, if any.
-          This will be reset by the ptrace hook upon any
-          subsequent ptrace_attach operations. */
-       tsec2->ptrace_sid = tsec1->ptrace_sid;
-
        return 0;
 }
 
@@ -3105,7 +3222,7 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 
 static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 {
-       return secondary_ops->task_post_setuid(id0,id1,id2,flags);
+       return secondary_ops->task_post_setuid(id0, id1, id2, flags);
 }
 
 static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -3131,7 +3248,8 @@ static int selinux_task_getsid(struct task_struct *p)
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       selinux_get_task_sid(p, secid);
+       struct task_security_struct *tsec = p->security;
+       *secid = tsec->sid;
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -3148,7 +3266,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
        if (rc)
                return rc;
 
-       return task_has_perm(current,p, PROCESS__SETSCHED);
+       return task_has_perm(current, p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3218,9 +3336,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        if (rc)
                return rc;
 
-       if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
-               return 0;
-
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
@@ -3237,12 +3352,13 @@ static int selinux_task_prctl(int option,
                              unsigned long arg2,
                              unsigned long arg3,
                              unsigned long arg4,
-                             unsigned long arg5)
+                             unsigned long arg5,
+                             long *rc_p)
 {
        /* 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 0;
+       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
 }
 
 static int selinux_task_wait(struct task_struct *p)
@@ -3252,7 +3368,7 @@ static int selinux_task_wait(struct task_struct *p)
 
 static void selinux_task_reparent_to_init(struct task_struct *p)
 {
-       struct task_security_struct *tsec;
+       struct task_security_struct *tsec;
 
        secondary_ops->task_reparent_to_init(p);
 
@@ -3297,11 +3413,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                *proto = ih->protocol;
 
        switch (ih->protocol) {
-        case IPPROTO_TCP: {
-               struct tcphdr _tcph, *th;
+       case IPPROTO_TCP: {
+               struct tcphdr _tcph, *th;
 
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
 
                offset += ihlen;
                th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
@@ -3311,23 +3427,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                ad->u.net.sport = th->source;
                ad->u.net.dport = th->dest;
                break;
-        }
-        
-        case IPPROTO_UDP: {
-               struct udphdr _udph, *uh;
-               
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-                       
+       }
+
+       case IPPROTO_UDP: {
+               struct udphdr _udph, *uh;
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
                offset += ihlen;
-               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
                if (uh == NULL)
-                       break;  
+                       break;
 
-               ad->u.net.sport = uh->source;
-               ad->u.net.dport = uh->dest;
-               break;
-        }
+               ad->u.net.sport = uh->source;
+               ad->u.net.dport = uh->dest;
+               break;
+       }
 
        case IPPROTO_DCCP: {
                struct dccp_hdr _dccph, *dh;
@@ -3343,11 +3459,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                ad->u.net.sport = dh->dccph_sport;
                ad->u.net.dport = dh->dccph_dport;
                break;
-        }
+       }
 
-        default:
-               break;
-        }
+       default:
+               break;
+       }
 out:
        return ret;
 }
@@ -3382,7 +3498,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
 
        switch (nexthdr) {
        case IPPROTO_TCP: {
-               struct tcphdr _tcph, *th;
+               struct tcphdr _tcph, *th;
 
                th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
                if (th == NULL)
@@ -3415,7 +3531,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
                ad->u.net.sport = dh->dccph_sport;
                ad->u.net.dport = dh->dccph_dport;
                break;
-        }
+       }
 
        /* includes fragments */
        default:
@@ -3428,38 +3544,44 @@ out:
 #endif /* IPV6 */
 
 static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
-                            char **addrp, int src, u8 *proto)
+                            char **_addrp, int src, u8 *proto)
 {
-       int ret = 0;
+       char *addrp;
+       int ret;
 
        switch (ad->u.net.family) {
        case PF_INET:
                ret = selinux_parse_skb_ipv4(skb, ad, proto);
-               if (ret || !addrp)
-                       break;
-               *addrp = (char *)(src ? &ad->u.net.v4info.saddr :
-                                       &ad->u.net.v4info.daddr);
-               break;
+               if (ret)
+                       goto parse_error;
+               addrp = (char *)(src ? &ad->u.net.v4info.saddr :
+                                      &ad->u.net.v4info.daddr);
+               goto okay;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case PF_INET6:
                ret = selinux_parse_skb_ipv6(skb, ad, proto);
-               if (ret || !addrp)
-                       break;
-               *addrp = (char *)(src ? &ad->u.net.v6info.saddr :
-                                       &ad->u.net.v6info.daddr);
-               break;
+               if (ret)
+                       goto parse_error;
+               addrp = (char *)(src ? &ad->u.net.v6info.saddr :
+                                      &ad->u.net.v6info.daddr);
+               goto okay;
 #endif /* IPV6 */
        default:
-               break;
+               addrp = NULL;
+               goto okay;
        }
 
-       if (unlikely(ret))
-               printk(KERN_WARNING
-                      "SELinux: failure in selinux_parse_skb(),"
-                      " unable to parse packet\n");
-
+parse_error:
+       printk(KERN_WARNING
+              "SELinux: failure in selinux_parse_skb(),"
+              " unable to parse packet\n");
        return ret;
+
+okay:
+       if (_addrp)
+               *_addrp = addrp;
+       return 0;
 }
 
 /**
@@ -3513,7 +3635,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
        if (isec->sid == SECINITSID_KERNEL)
                goto out;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = sock->sk;
        err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
 
@@ -3596,7 +3718,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
                struct sock *sk = sock->sk;
-               u32 sid, node_perm, addrlen;
+               u32 sid, node_perm;
 
                tsec = current->security;
                isec = SOCK_INODE(sock)->i_security;
@@ -3604,12 +3726,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
-                       addrlen = sizeof(addr4->sin_addr.s_addr);
                        addrp = (char *)&addr4->sin_addr.s_addr;
                } else {
                        addr6 = (struct sockaddr_in6 *)address;
                        snum = ntohs(addr6->sin6_port);
-                       addrlen = sizeof(addr6->sin6_addr.s6_addr);
                        addrp = (char *)&addr6->sin6_addr.s6_addr;
                }
 
@@ -3619,13 +3739,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        inet_get_local_port_range(&low, &high);
 
                        if (snum < max(PROT_SOCK, low) || snum > high) {
-                               err = security_port_sid(sk->sk_family,
-                                                       sk->sk_type,
-                                                       sk->sk_protocol, snum,
-                                                       &sid);
+                               err = sel_netport_sid(sk->sk_protocol,
+                                                     snum, &sid);
                                if (err)
                                        goto out;
-                               AVC_AUDIT_DATA_INIT(&ad,NET);
+                               AVC_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
                                err = avc_has_perm(isec->sid, sid,
@@ -3635,12 +3753,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                        goto out;
                        }
                }
-               
-               switch(isec->sclass) {
+
+               switch (isec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
-                       
+
                case SECCLASS_UDP_SOCKET:
                        node_perm = UDP_SOCKET__NODE_BIND;
                        break;
@@ -3653,12 +3771,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        node_perm = RAWIP_SOCKET__NODE_BIND;
                        break;
                }
-               
+
                err = sel_netnode_sid(addrp, family, &sid);
                if (err)
                        goto out;
-               
-               AVC_AUDIT_DATA_INIT(&ad,NET);
+
+               AVC_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.sport = htons(snum);
                ad.u.net.family = family;
 
@@ -3668,7 +3786,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
                err = avc_has_perm(isec->sid, sid,
-                                  isec->sclass, node_perm, &ad);
+                                  isec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3678,6 +3796,7 @@ out:
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        struct inode_security_struct *isec;
        int err;
 
@@ -3691,7 +3810,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        isec = SOCK_INODE(sock)->i_security;
        if (isec->sclass == SECCLASS_TCP_SOCKET ||
            isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct sock *sk = sock->sk;
                struct avc_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3710,15 +3828,14 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                        snum = ntohs(addr6->sin6_port);
                }
 
-               err = security_port_sid(sk->sk_family, sk->sk_type,
-                                       sk->sk_protocol, snum, &sid);
+               err = sel_netport_sid(sk->sk_protocol, snum, &sid);
                if (err)
                        goto out;
 
                perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               AVC_AUDIT_DATA_INIT(&ad,NET);
+               AVC_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);
@@ -3726,6 +3843,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                        goto out;
        }
 
+       err = selinux_netlbl_socket_connect(sk, address);
+
 out:
        return err;
 }
@@ -3756,7 +3875,7 @@ 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 size)
 {
        int rc;
 
@@ -3783,7 +3902,7 @@ static int selinux_socket_getpeername(struct socket *sock)
        return socket_has_perm(current, sock, SOCKET__GETATTR);
 }
 
-static int selinux_socket_setsockopt(struct socket *sock,int level,int optname)
+static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
@@ -3822,7 +3941,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3834,7 +3953,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        /* 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;
@@ -3854,7 +3973,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3932,7 +4051,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
        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;
@@ -3942,9 +4061,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 
        if (!recv_perm)
                return 0;
-       err = security_port_sid(sk->sk_family, sk->sk_type,
-                               sk->sk_protocol, ntohs(ad->u.net.sport),
-                               &port_sid);
+       err = sel_netport_sid(sk->sk_protocol,
+                             ntohs(ad->u.net.sport), &port_sid);
        if (unlikely(err)) {
                printk(KERN_WARNING
                       "SELinux: failure in"
@@ -3956,20 +4074,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 }
 
 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
-                                      struct avc_audit_data *ad,
-                                      u16 family, char *addrp)
+                                      u16 family)
 {
        int err;
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
+       struct avc_audit_data ad;
+       char *addrp;
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = 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,
+               err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
                                                           family, addrp);
        else
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
-                                  PACKET__RECV, ad);
+                                  PACKET__RECV, &ad);
        if (err)
                return err;
 
@@ -3978,12 +4104,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                if (err)
                        return err;
                err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, ad);
+                                  SECCLASS_PEER, PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, 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);
+               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
        }
 
        return err;
@@ -3997,6 +4125,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        u32 sk_sid = sksec->sid;
        struct avc_audit_data ad;
        char *addrp;
+       u8 secmark_active;
+       u8 peerlbl_active;
 
        if (family != PF_INET && family != PF_INET6)
                return 0;
@@ -4005,6 +4135,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
                family = PF_INET;
 
+       /* If any sort of compatibility mode is enabled then handoff processing
+        * 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)
+               return selinux_sock_rcv_skb_compat(sk, skb, family);
+
+       secmark_active = selinux_secmark_enabled();
+       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       if (!secmark_active && !peerlbl_active)
+               return 0;
+
        AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
@@ -4012,15 +4154,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (err)
                return err;
 
-       /* If any sort of compatibility mode is enabled then handoff processing
-        * 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)
-               return selinux_sock_rcv_skb_compat(sk, skb, &ad,
-                                                  family, addrp);
-
-       if (netlbl_enabled() || selinux_xfrm_enabled()) {
+       if (peerlbl_active) {
                u32 peer_sid;
 
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4028,13 +4162,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        return err;
                err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
                                               peer_sid, &ad);
-               if (err)
+               if (err) {
+                       selinux_netlbl_err(skb, err, 0);
                        return err;
+               }
                err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
                                   PEER__RECV, &ad);
+               if (err)
+                       selinux_netlbl_err(skb, err, 0);
        }
 
-       if (selinux_secmark_enabled()) {
+       if (secmark_active) {
                err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
                                   PACKET__RECV, &ad);
                if (err)
@@ -4084,7 +4222,7 @@ out_len:
                err = -EFAULT;
 
        kfree(scontext);
-out:   
+out:
        return err;
 }
 
@@ -4093,15 +4231,17 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
        u32 peer_secid = SECSID_NULL;
        u16 family;
 
-       if (sock)
+       if (skb && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+       else if (skb && skb->protocol == htons(ETH_P_IPV6))
+               family = PF_INET6;
+       else if (sock)
                family = sock->sk->sk_family;
-       else if (skb && skb->sk)
-               family = skb->sk->sk_family;
        else
                goto out;
 
        if (sock && family == PF_UNIX)
-               selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+               selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
        else if (skb)
                selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -4131,7 +4271,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
        newssec->peer_sid = ssec->peer_sid;
        newssec->sclass = ssec->sclass;
 
-       selinux_netlbl_sk_security_clone(ssec, newssec);
+       selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
 }
 
 static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4145,7 +4285,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
        }
 }
 
-static void selinux_sock_graft(struct socksk, struct socket *parent)
+static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
        struct sk_security_struct *sksec = sk->sk_security;
@@ -4154,8 +4294,6 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent)
            sk->sk_family == PF_UNIX)
                isec->sid = sksec->sid;
        sksec->sclass = isec->sclass;
-
-       selinux_netlbl_sock_graft(sk, parent);
 }
 
 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
@@ -4163,10 +4301,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 {
        struct sk_security_struct *sksec = sk->sk_security;
        int err;
+       u16 family = sk->sk_family;
        u32 newsid;
        u32 peersid;
 
-       err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       err = selinux_skb_peerlbl_sid(skb, family, &peersid);
        if (err)
                return err;
        if (peersid == SECSID_NULL) {
@@ -4201,12 +4344,18 @@ static void selinux_inet_csk_clone(struct sock *newsk,
        selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
 }
 
-static void selinux_inet_conn_established(struct sock *sk,
-                               struct sk_buff *skb)
+static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
+       u16 family = sk->sk_family;
        struct sk_security_struct *sksec = sk->sk_security;
 
-       selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
+
+       selinux_netlbl_inet_conn_established(sk, family);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4222,13 +4371,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        struct nlmsghdr *nlh;
        struct socket *sock = sk->sk_socket;
        struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
-       
+
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
                goto out;
        }
        nlh = nlmsg_hdr(skb);
-       
+
        err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
@@ -4256,39 +4405,54 @@ out:
 static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
                                       u16 family)
 {
+       int err;
        char *addrp;
        u32 peer_sid;
        struct avc_audit_data ad;
        u8 secmark_active;
+       u8 netlbl_active;
        u8 peerlbl_active;
 
        if (!selinux_policycap_netpeer)
                return NF_ACCEPT;
 
        secmark_active = selinux_secmark_enabled();
-       peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
+       netlbl_active = netlbl_enabled();
+       peerlbl_active = netlbl_active || selinux_xfrm_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
+       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
+               return NF_DROP;
+
        AVC_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)
                return NF_DROP;
 
-       if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
-               return NF_DROP;
-
-       if (peerlbl_active)
-               if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-                                            peer_sid, &ad) != 0)
+       if (peerlbl_active) {
+               err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
+                                              peer_sid, &ad);
+               if (err) {
+                       selinux_netlbl_err(skb, err, 1);
                        return NF_DROP;
+               }
+       }
 
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
                        return NF_DROP;
 
+       if (netlbl_active)
+               /* we do this in the FORWARD path and not the POST_ROUTING
+                * path because we want to make sure we apply the necessary
+                * labeling before IPsec is applied so we can leverage AH
+                * protection */
+               if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
+                       return NF_DROP;
+
        return NF_ACCEPT;
 }
 
@@ -4312,6 +4476,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
 }
 #endif /* IPV6 */
 
+static unsigned int selinux_ip_output(struct sk_buff *skb,
+                                     u16 family)
+{
+       u32 sid;
+
+       if (!netlbl_enabled())
+               return NF_ACCEPT;
+
+       /* we do this in the LOCAL_OUT path and not the POST_ROUTING path
+        * because we want to make sure we apply the necessary labeling
+        * before IPsec is applied so we can leverage AH protection */
+       if (skb->sk) {
+               struct sk_security_struct *sksec = skb->sk->sk_security;
+               sid = sksec->sid;
+       } else
+               sid = SECINITSID_KERNEL;
+       if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
+               return NF_DROP;
+
+       return NF_ACCEPT;
+}
+
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
+                                       struct sk_buff *skb,
+                                       const struct net_device *in,
+                                       const struct net_device *out,
+                                       int (*okfn)(struct sk_buff *))
+{
+       return selinux_ip_output(skb, PF_INET);
+}
+
 static int selinux_ip_postroute_iptables_compat(struct sock *sk,
                                                int ifindex,
                                                struct avc_audit_data *ad,
@@ -4354,7 +4549,7 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
                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;
@@ -4365,9 +4560,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
        if (send_perm != 0)
                return 0;
 
-       err = security_port_sid(sk->sk_family, sk->sk_type,
-                               sk->sk_protocol, ntohs(ad->u.net.dport),
-                               &port_sid);
+       err = sel_netport_sid(sk->sk_protocol,
+                             ntohs(ad->u.net.dport), &port_sid);
        if (unlikely(err)) {
                printk(KERN_WARNING
                       "SELinux: failure in"
@@ -4380,30 +4574,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
 
 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
-                                               struct avc_audit_data *ad,
-                                               u16 family,
-                                               char *addrp,
-                                               u8 proto)
+                                               u16 family)
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
+       struct avc_audit_data ad;
+       char *addrp;
+       u8 proto;
 
        if (sk == NULL)
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
+       AVC_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))
+                                                        &ad, family, addrp))
                        return NF_DROP;
        } else {
                if (avc_has_perm(sksec->sid, skb->secmark,
-                                SECCLASS_PACKET, PACKET__SEND, ad))
+                                SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP;
        }
 
        if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
+               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
                        return NF_DROP;
 
        return NF_ACCEPT;
@@ -4417,24 +4617,16 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        struct sock *sk;
        struct avc_audit_data ad;
        char *addrp;
-       u8 proto;
        u8 secmark_active;
        u8 peerlbl_active;
 
-       AVC_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 any sort of compatibility mode is enabled then handoff processing
         * to the selinux_ip_postroute_compat() function to deal with the
         * special handling.  We do this in an attempt to keep this function
         * as fast and as clean as possible. */
        if (selinux_compat_net || !selinux_policycap_netpeer)
-               return selinux_ip_postroute_compat(skb, ifindex, &ad,
-                                                  family, addrp, proto);
-
+               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
@@ -4443,27 +4635,51 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         *       is NULL, in this case go ahead and apply access control. */
        if (skb->dst != NULL && skb->dst->xfrm != NULL)
                return NF_ACCEPT;
-
+#endif
        secmark_active = selinux_secmark_enabled();
        peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
        if (!secmark_active && !peerlbl_active)
                return NF_ACCEPT;
 
-       /* if the packet is locally generated (skb->sk != NULL) then use the
-        * socket's label as the peer label, otherwise the packet is being
-        * forwarded through this system and we need to fetch the peer label
-        * directly from the packet */
+       /* if the packet is being forwarded then get the peer label from the
+        * packet itself; otherwise check to see if it is from a local
+        * application or the kernel, if from an application get the peer label
+        * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
-       if (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 (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
+                               return NF_DROP;
+               } else
+                       peer_sid = SECINITSID_KERNEL;
+       } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
                secmark_perm = PACKET__SEND;
-       } else {
-               if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
-                               return NF_DROP;
-               secmark_perm = PACKET__FORWARD_OUT;
        }
 
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = ifindex;
+       ad.u.net.family = family;
+       if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
+               return NF_DROP;
+
        if (secmark_active)
                if (avc_has_perm(peer_sid, skb->secmark,
                                 SECCLASS_PACKET, secmark_perm, &ad))
@@ -4538,7 +4754,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability)
        ad.u.cap = capability;
 
        return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
-                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
+                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
 }
 
 static int ipc_alloc_security(struct task_struct *task,
@@ -4553,7 +4769,6 @@ static int ipc_alloc_security(struct task_struct *task,
                return -ENOMEM;
 
        isec->sclass = sclass;
-       isec->ipc_perm = perm;
        isec->sid = tsec->sid;
        perm->security = isec;
 
@@ -4575,7 +4790,6 @@ static int msg_msg_alloc_security(struct msg_msg *msg)
        if (!msec)
                return -ENOMEM;
 
-       msec->msg = msg;
        msec->sid = SECINITSID_UNLABELED;
        msg->security = msec;
 
@@ -4632,7 +4846,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
        isec = msq->q_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = msq->q_perm.key;
+       ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
@@ -4669,7 +4883,7 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
        int err;
        int perms;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case MSG_INFO:
                /* No specific object, just general system-wide information. */
@@ -4753,7 +4967,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
        msec = msg->security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = msq->q_perm.key;
+       ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid,
                          SECCLASS_MSGQ, MSGQ__READ, &ad);
@@ -4779,7 +4993,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
        isec = shp->shm_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = shp->shm_perm.key;
+       ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
@@ -4817,7 +5031,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
        int perms;
        int err;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SHM_INFO:
                /* No specific object, just general system-wide information. */
@@ -4878,7 +5092,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
        isec = sma->sem_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = sma->sem_perm.key;
+       ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
@@ -4916,7 +5130,7 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd)
        int err;
        u32 perms;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SEM_INFO:
                /* No specific object, just general system-wide information. */
@@ -4981,25 +5195,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
        return ipc_has_perm(ipcp, av);
 }
 
-/* module stacking operations */
-static int selinux_register_security (const char *name, struct security_operations *ops)
+static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 {
-       if (secondary_ops != original_ops) {
-               printk(KERN_ERR "%s:  There is already a secondary security "
-                      "module registered.\n", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       secondary_ops = ops;
-
-       printk(KERN_INFO "%s:  Registering secondary module %s\n",
-              __FUNCTION__,
-              name);
-
-       return 0;
+       struct ipc_security_struct *isec = ipcp->security;
+       *secid = isec->sid;
 }
 
-static void selinux_d_instantiate (struct dentry *dentry, struct inode *inode)
+static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 {
        if (inode)
                inode_doinit_with_dentry(inode, dentry);
@@ -5049,6 +5251,7 @@ static int selinux_setprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
+       struct task_struct *tracer;
        u32 sid = 0;
        int error;
        char *str = value;
@@ -5086,6 +5289,12 @@ static int selinux_setprocattr(struct task_struct *p,
                        size--;
                }
                error = security_context_to_sid(value, size, &sid);
+               if (error == -EINVAL && !strcmp(name, "fscreate")) {
+                       if (!capable(CAP_MAC_ADMIN))
+                               return error;
+                       error = security_context_to_sid_force(value, size,
+                                                             &sid);
+               }
                if (error)
                        return error;
        }
@@ -5113,47 +5322,61 @@ static int selinux_setprocattr(struct task_struct *p,
 
                if (sid == 0)
                        return -EINVAL;
-
-               /* Only allow single threaded processes to change context */
+               /*
+                * SELinux allows to change context in the following case only.
+                *  - Single threaded processes.
+                *  - Multi threaded processes intend to change its context into
+                *    more restricted domain (defined by TYPEBOUNDS statement).
+                */
                if (atomic_read(&p->mm->mm_users) != 1) {
                        struct task_struct *g, *t;
                        struct mm_struct *mm = p->mm;
                        read_lock(&tasklist_lock);
-                       do_each_thread(g, t)
+                       do_each_thread(g, t) {
                                if (t->mm == mm && t != p) {
                                        read_unlock(&tasklist_lock);
-                                       return -EPERM;
+                                       error = security_bounded_transition(tsec->sid, sid);
+                                       if (!error)
+                                               goto boundary_ok;
+
+                                       return error;
                                }
-                       while_each_thread(g, t);
+                       while_each_thread(g, t);
                        read_unlock(&tasklist_lock);
-                }
+               }
+boundary_ok:
 
                /* Check permissions for the transition. */
                error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
-                                    PROCESS__DYNTRANSITION, NULL);
+                                    PROCESS__DYNTRANSITION, NULL);
                if (error)
                        return error;
 
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and fail. */
                task_lock(p);
-               if (p->ptrace & PT_PTRACED) {
-                       error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
+               rcu_read_lock();
+               tracer = tracehook_tracer_task(p);
+               if (tracer != NULL) {
+                       struct task_security_struct *ptsec = tracer->security;
+                       u32 ptsid = ptsec->sid;
+                       rcu_read_unlock();
+                       error = avc_has_perm_noaudit(ptsid, sid,
                                                     SECCLASS_PROCESS,
                                                     PROCESS__PTRACE, 0, &avd);
                        if (!error)
                                tsec->sid = sid;
                        task_unlock(p);
-                       avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS,
+                       avc_audit(ptsid, sid, SECCLASS_PROCESS,
                                  PROCESS__PTRACE, &avd, error, NULL);
                        if (error)
                                return error;
                } else {
+                       rcu_read_unlock();
                        tsec->sid = sid;
                        task_unlock(p);
                }
-       }
-       else
+       } else
                return -EINVAL;
 
        return size;
@@ -5164,7 +5387,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        return security_sid_to_context(secid, secdata, seclen);
 }
 
-static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
        return security_context_to_sid(secdata, seclen, secid);
 }
@@ -5186,7 +5409,6 @@ static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
        if (!ksec)
                return -ENOMEM;
 
-       ksec->obj = k;
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
@@ -5227,10 +5449,27 @@ static int selinux_key_permission(key_ref_t key_ref,
                            SECCLASS_KEY, perm, NULL);
 }
 
+static int selinux_key_getsecurity(struct key *key, char **_buffer)
+{
+       struct key_security_struct *ksec = key->security;
+       char *context = NULL;
+       unsigned len;
+       int rc;
+
+       rc = security_sid_to_context(ksec->sid, &context, &len);
+       if (!rc)
+               rc = len;
+       *_buffer = context;
+       return rc;
+}
+
 #endif
 
 static struct security_operations selinux_ops = {
-       .ptrace =                       selinux_ptrace,
+       .name =                         "selinux",
+
+       .ptrace_may_access =            selinux_ptrace_may_access,
+       .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset_check =                 selinux_capset_check,
        .capset_set =                   selinux_capset_set,
@@ -5242,7 +5481,7 @@ static struct security_operations selinux_ops = {
        .vm_enough_memory =             selinux_vm_enough_memory,
 
        .netlink_send =                 selinux_netlink_send,
-        .netlink_recv =                        selinux_netlink_recv,
+       .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_alloc_security =          selinux_bprm_alloc_security,
        .bprm_free_security =           selinux_bprm_free_security,
@@ -5255,13 +5494,13 @@ static struct security_operations selinux_ops = {
        .sb_alloc_security =            selinux_sb_alloc_security,
        .sb_free_security =             selinux_sb_free_security,
        .sb_copy_data =                 selinux_sb_copy_data,
-       .sb_kern_mount =                selinux_sb_kern_mount,
+       .sb_kern_mount =                selinux_sb_kern_mount,
+       .sb_show_options =              selinux_sb_show_options,
        .sb_statfs =                    selinux_sb_statfs,
        .sb_mount =                     selinux_mount,
        .sb_umount =                    selinux_umount,
-       .sb_get_mnt_opts =              selinux_get_mnt_opts,
        .sb_set_mnt_opts =              selinux_set_mnt_opts,
-       .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
+       .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
        .sb_parse_opts_str =            selinux_parse_opts_str,
 
 
@@ -5286,11 +5525,12 @@ static struct security_operations selinux_ops = {
        .inode_getxattr =               selinux_inode_getxattr,
        .inode_listxattr =              selinux_inode_listxattr,
        .inode_removexattr =            selinux_inode_removexattr,
-       .inode_getsecurity =            selinux_inode_getsecurity,
-       .inode_setsecurity =            selinux_inode_setsecurity,
-       .inode_listsecurity =           selinux_inode_listsecurity,
+       .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,
        .file_alloc_security =          selinux_file_alloc_security,
@@ -5304,7 +5544,7 @@ static struct security_operations selinux_ops = {
        .file_send_sigiotask =          selinux_file_send_sigiotask,
        .file_receive =                 selinux_file_receive,
 
-       .dentry_open =                  selinux_dentry_open,
+       .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
        .task_alloc_security =          selinux_task_alloc_security,
@@ -5314,7 +5554,7 @@ static struct security_operations selinux_ops = {
        .task_setgid =                  selinux_task_setgid,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
-       .task_getsid =                  selinux_task_getsid,
+       .task_getsid =                  selinux_task_getsid,
        .task_getsecid =                selinux_task_getsecid,
        .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
@@ -5328,9 +5568,10 @@ static struct security_operations selinux_ops = {
        .task_wait =                    selinux_task_wait,
        .task_prctl =                   selinux_task_prctl,
        .task_reparent_to_init =        selinux_task_reparent_to_init,
-       .task_to_inode =                selinux_task_to_inode,
+       .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
+       .ipc_getsecid =                 selinux_ipc_getsecid,
 
        .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
        .msg_msg_free_security =        selinux_msg_msg_free_security,
@@ -5348,24 +5589,22 @@ static struct security_operations selinux_ops = {
        .shm_shmctl =                   selinux_shm_shmctl,
        .shm_shmat =                    selinux_shm_shmat,
 
-       .sem_alloc_security =           selinux_sem_alloc_security,
-       .sem_free_security =            selinux_sem_free_security,
+       .sem_alloc_security =           selinux_sem_alloc_security,
+       .sem_free_security =            selinux_sem_free_security,
        .sem_associate =                selinux_sem_associate,
        .sem_semctl =                   selinux_sem_semctl,
        .sem_semop =                    selinux_sem_semop,
 
-       .register_security =            selinux_register_security,
-
-       .d_instantiate =                selinux_d_instantiate,
+       .d_instantiate =                selinux_d_instantiate,
 
-       .getprocattr =                  selinux_getprocattr,
-       .setprocattr =                  selinux_setprocattr,
+       .getprocattr =                  selinux_getprocattr,
+       .setprocattr =                  selinux_setprocattr,
 
        .secid_to_secctx =              selinux_secid_to_secctx,
        .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
 
-        .unix_stream_connect =         selinux_socket_unix_stream_connect,
+       .unix_stream_connect =          selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
 
        .socket_create =                selinux_socket_create,
@@ -5387,7 +5626,7 @@ static struct security_operations selinux_ops = {
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_clone_security =            selinux_sk_clone_security,
-       .sk_getsecid =                  selinux_sk_getsecid,
+       .sk_getsecid =                  selinux_sk_getsecid,
        .sock_graft =                   selinux_sock_graft,
        .inet_conn_request =            selinux_inet_conn_request,
        .inet_csk_clone =               selinux_inet_csk_clone,
@@ -5402,15 +5641,23 @@ static struct security_operations selinux_ops = {
        .xfrm_state_alloc_security =    selinux_xfrm_state_alloc,
        .xfrm_state_free_security =     selinux_xfrm_state_free,
        .xfrm_state_delete_security =   selinux_xfrm_state_delete,
-       .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
+       .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
        .xfrm_state_pol_flow_match =    selinux_xfrm_state_pol_flow_match,
        .xfrm_decode_session =          selinux_xfrm_decode_session,
 #endif
 
 #ifdef CONFIG_KEYS
-       .key_alloc =                    selinux_key_alloc,
-       .key_free =                     selinux_key_free,
-       .key_permission =               selinux_key_permission,
+       .key_alloc =                    selinux_key_alloc,
+       .key_free =                     selinux_key_free,
+       .key_permission =               selinux_key_permission,
+       .key_getsecurity =              selinux_key_getsecurity,
+#endif
+
+#ifdef CONFIG_AUDIT
+       .audit_rule_init =              selinux_audit_rule_init,
+       .audit_rule_known =             selinux_audit_rule_known,
+       .audit_rule_match =             selinux_audit_rule_match,
+       .audit_rule_free =              selinux_audit_rule_free,
 #endif
 };
 
@@ -5418,6 +5665,11 @@ static __init int selinux_init(void)
 {
        struct task_security_struct *tsec;
 
+       if (!security_module_enable(&selinux_ops)) {
+               selinux_enabled = 0;
+               return 0;
+       }
+
        if (!selinux_enabled) {
                printk(KERN_INFO "SELinux:  Disabled at boot.\n");
                return 0;
@@ -5436,25 +5688,16 @@ static __init int selinux_init(void)
                                            0, SLAB_PANIC, NULL);
        avc_init();
 
-       original_ops = secondary_ops = security_ops;
+       secondary_ops = security_ops;
        if (!secondary_ops)
-               panic ("SELinux: No initial security operations\n");
-       if (register_security (&selinux_ops))
+               panic("SELinux: No initial security operations\n");
+       if (register_security(&selinux_ops))
                panic("SELinux: Unable to register with kernel.\n");
 
-       if (selinux_enforcing) {
+       if (selinux_enforcing)
                printk(KERN_DEBUG "SELinux:  Starting in enforcing mode\n");
-       } else {
+       else
                printk(KERN_DEBUG "SELinux:  Starting in permissive mode\n");
-       }
-
-#ifdef CONFIG_KEYS
-       /* Add security information to initial keyrings */
-       selinux_key_alloc(&root_user_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-       selinux_key_alloc(&root_session_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-#endif
 
        return 0;
 }
@@ -5471,8 +5714,8 @@ 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 superblock_security_struct,
+                                          list);
                struct super_block *sb = sbsec->sb;
                sb->s_count++;
                spin_unlock(&sb_security_lock);
@@ -5510,6 +5753,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
                .pf =           PF_INET,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+       {
+               .hook =         selinux_ipv4_output,
+               .owner =        THIS_MODULE,
+               .pf =           PF_INET,
+               .hooknum =      NF_INET_LOCAL_OUT,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
        }
 };
 
@@ -5537,27 +5787,20 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
 static int __init selinux_nf_ip_init(void)
 {
        int err = 0;
-       u32 iter;
 
        if (!selinux_enabled)
                goto out;
 
        printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-       for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
-               err = nf_register_hook(&selinux_ipv4_ops[iter]);
-               if (err)
-                       panic("SELinux: nf_register_hook for IPv4: error %d\n",
-                             err);
-       }
+       err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
+       if (err)
+               panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
-               err = nf_register_hook(&selinux_ipv6_ops[iter]);
-               if (err)
-                       panic("SELinux: nf_register_hook for IPv6: error %d\n",
-                             err);
-       }
+       err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
+       if (err)
+               panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
 #endif /* IPV6 */
 
 out:
@@ -5569,15 +5812,11 @@ __initcall(selinux_nf_ip_init);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 static void selinux_nf_ip_exit(void)
 {
-       u32 iter;
-
        printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
-       for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++)
-               nf_unregister_hook(&selinux_ipv4_ops[iter]);
+       nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++)
-               nf_unregister_hook(&selinux_ipv6_ops[iter]);
+       nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
 #endif /* IPV6 */
 }
 #endif
@@ -5591,10 +5830,11 @@ static void selinux_nf_ip_exit(void)
 #endif /* CONFIG_NETFILTER */
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
+static int selinux_disabled;
+
 int selinux_disable(void)
 {
        extern void exit_sel_fs(void);
-       static int selinux_disabled = 0;
 
        if (ss_initialized) {
                /* Not permitted after initial policy load. */
@@ -5623,5 +5863,3 @@ int selinux_disable(void)
        return 0;
 }
 #endif
-
-