fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / security / selinux / hooks.c
index f844e40..e9c61d1 100644 (file)
  *
  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
  *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ *                          <dgoeddel@trustedcs.com>
+ *  Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ *                     Paul Moore, <paul.moore@hp.com>
  *
  *     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.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #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>
@@ -48,7 +51,6 @@
 #include <net/ip.h>            /* for sysctl_local_port_range[] */
 #include <net/tcp.h>           /* struct or_callable used in sock_rcv_skb */
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 #include <asm/ioctls.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
@@ -56,6 +58,7 @@
 #include <linux/netlink.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/dccp.h>
 #include <linux/quota.h>
 #include <linux/un.h>          /* for Unix socket types */
 #include <net/af_unix.h>       /* for Unix socket types */
 #include <net/ipv6.h>
 #include <linux/hugetlb.h>
 #include <linux/personality.h>
+#include <linux/sysctl.h>
+#include <linux/audit.h>
+#include <linux/string.h>
+#include <linux/selinux.h>
+#include <linux/mutex.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "netif.h"
+#include "xfrm.h"
+#include "selinux_netlabel.h"
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
-extern int policydb_loaded_version;
+extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
+extern int selinux_compat_net;
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing = 0;
@@ -95,6 +106,8 @@ static int __init selinux_enabled_setup(char *str)
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
+#else
+int selinux_enabled = 1;
 #endif
 
 /* Original (dummy) security module. */
@@ -109,7 +122,35 @@ static struct security_operations *secondary_ops = NULL;
 /* Lists of inode and superblock security structures initialized
    before the policy was loaded. */
 static LIST_HEAD(superblock_security_head);
-static spinlock_t sb_security_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sb_security_lock);
+
+static struct kmem_cache *sel_inode_cache;
+
+/* Return security context for a given sid or just the context 
+   length if the buffer is null or length is 0 */
+static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
+{
+       char *context;
+       unsigned len;
+       int rc;
+
+       rc = security_sid_to_context(sid, &context, &len);
+       if (rc)
+               return rc;
+
+       if (!buffer || !size)
+               goto getsecurity_exit;
+
+       if (size < len) {
+               len = -ERANGE;
+               goto getsecurity_exit;
+       }
+       memcpy(buffer, context, len);
+
+getsecurity_exit:
+       kfree(context);
+       return len;
+}
 
 /* Allocate and free functions for each kind of security blob. */
 
@@ -117,14 +158,12 @@ static int task_alloc_security(struct task_struct *task)
 {
        struct task_security_struct *tsec;
 
-       tsec = kmalloc(sizeof(struct task_security_struct), GFP_KERNEL);
+       tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
        if (!tsec)
                return -ENOMEM;
 
-       memset(tsec, 0, sizeof(struct task_security_struct));
-       tsec->magic = SELINUX_MAGIC;
        tsec->task = task;
-       tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
+       tsec->osid = tsec->sid = SECINITSID_UNLABELED;
        task->security = tsec;
 
        return 0;
@@ -133,10 +172,6 @@ static int task_alloc_security(struct task_struct *task)
 static void task_free_security(struct task_struct *task)
 {
        struct task_security_struct *tsec = task->security;
-
-       if (!tsec || tsec->magic != SELINUX_MAGIC)
-               return;
-
        task->security = NULL;
        kfree(tsec);
 }
@@ -146,21 +181,17 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
+       isec = kmem_cache_alloc(sel_inode_cache, GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
-       memset(isec, 0, sizeof(struct inode_security_struct));
-       init_MUTEX(&isec->sem);
+       memset(isec, 0, sizeof(*isec));
+       mutex_init(&isec->lock);
        INIT_LIST_HEAD(&isec->list);
-       isec->magic = SELINUX_MAGIC;
        isec->inode = inode;
        isec->sid = SECINITSID_UNLABELED;
        isec->sclass = SECCLASS_FILE;
-       if (tsec && tsec->magic == SELINUX_MAGIC)
-               isec->task_sid = tsec->sid;
-       else
-               isec->task_sid = SECINITSID_UNLABELED;
+       isec->task_sid = tsec->sid;
        inode->i_security = isec;
 
        return 0;
@@ -171,16 +202,13 @@ static void inode_free_security(struct inode *inode)
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec = inode->i_sb->s_security;
 
-       if (!isec || isec->magic != SELINUX_MAGIC)
-               return;
-
        spin_lock(&sbsec->isec_lock);
        if (!list_empty(&isec->list))
                list_del_init(&isec->list);
        spin_unlock(&sbsec->isec_lock);
 
        inode->i_security = NULL;
-       kfree(isec);
+       kmem_cache_free(sel_inode_cache, isec);
 }
 
 static int file_alloc_security(struct file *file)
@@ -188,20 +216,13 @@ static int file_alloc_security(struct file *file)
        struct task_security_struct *tsec = current->security;
        struct file_security_struct *fsec;
 
-       fsec = kmalloc(sizeof(struct file_security_struct), GFP_ATOMIC);
+       fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
        if (!fsec)
                return -ENOMEM;
 
-       memset(fsec, 0, sizeof(struct file_security_struct));
-       fsec->magic = SELINUX_MAGIC;
        fsec->file = file;
-       if (tsec && tsec->magic == SELINUX_MAGIC) {
-               fsec->sid = tsec->sid;
-               fsec->fown_sid = tsec->sid;
-       } else {
-               fsec->sid = SECINITSID_UNLABELED;
-               fsec->fown_sid = SECINITSID_UNLABELED;
-       }
+       fsec->sid = tsec->sid;
+       fsec->fown_sid = tsec->sid;
        file->f_security = fsec;
 
        return 0;
@@ -210,10 +231,6 @@ static int file_alloc_security(struct file *file)
 static void file_free_security(struct file *file)
 {
        struct file_security_struct *fsec = file->f_security;
-
-       if (!fsec || fsec->magic != SELINUX_MAGIC)
-               return;
-
        file->f_security = NULL;
        kfree(fsec);
 }
@@ -222,19 +239,18 @@ static int superblock_alloc_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec;
 
-       sbsec = kmalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
+       sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
        if (!sbsec)
                return -ENOMEM;
 
-       memset(sbsec, 0, sizeof(struct superblock_security_struct));
-       init_MUTEX(&sbsec->sem);
+       mutex_init(&sbsec->lock);
        INIT_LIST_HEAD(&sbsec->list);
        INIT_LIST_HEAD(&sbsec->isec_head);
        spin_lock_init(&sbsec->isec_lock);
-       sbsec->magic = SELINUX_MAGIC;
        sbsec->sb = sb;
        sbsec->sid = SECINITSID_UNLABELED;
        sbsec->def_sid = SECINITSID_FILE;
+       sbsec->mntpoint_sid = SECINITSID_UNLABELED;
        sb->s_security = sbsec;
 
        return 0;
@@ -244,9 +260,6 @@ static void superblock_free_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
 
-       if (!sbsec || sbsec->magic != SELINUX_MAGIC)
-               return;
-
        spin_lock(&sb_security_lock);
        if (!list_empty(&sbsec->list))
                list_del_init(&sbsec->list);
@@ -256,24 +269,21 @@ static void superblock_free_security(struct super_block *sb)
        kfree(sbsec);
 }
 
-#ifdef CONFIG_SECURITY_NETWORK
-static int sk_alloc_security(struct sock *sk, int family, int priority)
+static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        struct sk_security_struct *ssec;
 
-       if (family != PF_UNIX)
-               return 0;
-
-       ssec = kmalloc(sizeof(*ssec), priority);
+       ssec = kzalloc(sizeof(*ssec), priority);
        if (!ssec)
                return -ENOMEM;
 
-       memset(ssec, 0, sizeof(*ssec));
-       ssec->magic = SELINUX_MAGIC;
        ssec->sk = sk;
        ssec->peer_sid = SECINITSID_UNLABELED;
+       ssec->sid = SECINITSID_UNLABELED;
        sk->sk_security = ssec;
 
+       selinux_netlbl_sk_security_init(ssec, family);
+
        return 0;
 }
 
@@ -281,13 +291,9 @@ static void sk_free_security(struct sock *sk)
 {
        struct sk_security_struct *ssec = sk->sk_security;
 
-       if (sk->sk_family != PF_UNIX || ssec->magic != SELINUX_MAGIC)
-               return;
-
        sk->sk_security = NULL;
        kfree(ssec);
 }
-#endif /* CONFIG_SECURITY_NETWORK */
 
 /* The security server must be initialized before
    any labeling or access decisions can be provided. */
@@ -315,19 +321,53 @@ enum {
        Opt_context = 1,
        Opt_fscontext = 2,
        Opt_defcontext = 4,
+       Opt_rootcontext = 8,
 };
 
 static match_table_t tokens = {
        {Opt_context, "context=%s"},
        {Opt_fscontext, "fscontext=%s"},
        {Opt_defcontext, "defcontext=%s"},
+       {Opt_rootcontext, "rootcontext=%s"},
 };
 
 #define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"
 
+static int may_context_mount_sb_relabel(u32 sid,
+                       struct superblock_security_struct *sbsec,
+                       struct task_security_struct *tsec)
+{
+       int rc;
+
+       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                         FILESYSTEM__RELABELFROM, NULL);
+       if (rc)
+               return rc;
+
+       rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
+                         FILESYSTEM__RELABELTO, NULL);
+       return rc;
+}
+
+static int may_context_mount_inode_relabel(u32 sid,
+                       struct superblock_security_struct *sbsec,
+                       struct task_security_struct *tsec)
+{
+       int rc;
+       rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                         FILESYSTEM__RELABELFROM, NULL);
+       if (rc)
+               return rc;
+
+       rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
+                         FILESYSTEM__ASSOCIATE, NULL);
+       return rc;
+}
+
 static int try_context_mount(struct super_block *sb, void *data)
 {
        char *context = NULL, *defcontext = NULL;
+       char *fscontext = NULL, *rootcontext = NULL;
        const char *name;
        u32 sid;
        int alloc = 0, rc = 0, seen = 0;
@@ -359,7 +399,7 @@ static int try_context_mount(struct super_block *sb, void *data)
                /* Standard string-based options. */
                char *p, *options = data;
 
-               while ((p = strsep(&options, ",")) != NULL) {
+               while ((p = strsep(&options, "|")) != NULL) {
                        int token;
                        substring_t args[MAX_OPT_ARGS];
 
@@ -370,7 +410,7 @@ static int try_context_mount(struct super_block *sb, void *data)
 
                        switch (token) {
                        case Opt_context:
-                               if (seen) {
+                               if (seen & (Opt_context|Opt_defcontext)) {
                                        rc = -EINVAL;
                                        printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
                                        goto out_free;
@@ -386,26 +426,35 @@ static int try_context_mount(struct super_block *sb, void *data)
                                break;
 
                        case Opt_fscontext:
-                               if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
+                               if (seen & Opt_fscontext) {
                                        rc = -EINVAL;
-                                       printk(KERN_WARNING "SELinux:  "
-                                              "fscontext option is invalid for"
-                                              " this filesystem type\n");
+                                       printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
                                        goto out_free;
                                }
-                               if (seen & (Opt_context|Opt_fscontext)) {
+                               fscontext = match_strdup(&args[0]);
+                               if (!fscontext) {
+                                       rc = -ENOMEM;
+                                       goto out_free;
+                               }
+                               if (!alloc)
+                                       alloc = 1;
+                               seen |= Opt_fscontext;
+                               break;
+
+                       case Opt_rootcontext:
+                               if (seen & Opt_rootcontext) {
                                        rc = -EINVAL;
                                        printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
                                        goto out_free;
                                }
-                               context = match_strdup(&args[0]);
-                               if (!context) {
+                               rootcontext = match_strdup(&args[0]);
+                               if (!rootcontext) {
                                        rc = -ENOMEM;
                                        goto out_free;
                                }
                                if (!alloc)
                                        alloc = 1;
-                               seen |= Opt_fscontext;
+                               seen |= Opt_rootcontext;
                                break;
 
                        case Opt_defcontext:
@@ -444,6 +493,28 @@ static int try_context_mount(struct super_block *sb, void *data)
        if (!seen)
                goto out;
 
+       /* sets the context of the superblock for the fs being mounted. */
+       if (fscontext) {
+               rc = security_context_to_sid(fscontext, strlen(fscontext), &sid);
+               if (rc) {
+                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                              "(%s) failed for (dev %s, type %s) errno=%d\n",
+                              fscontext, sb->s_id, name, rc);
+                       goto out_free;
+               }
+
+               rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+               if (rc)
+                       goto out_free;
+
+               sbsec->sid = sid;
+       }
+
+       /*
+        * Switch to using mount point labeling behavior.
+        * sets the label used on all file below the mountpoint, and will set
+        * the superblock context if not already set.
+        */
        if (context) {
                rc = security_context_to_sid(context, strlen(context), &sid);
                if (rc) {
@@ -453,20 +524,38 @@ static int try_context_mount(struct super_block *sb, void *data)
                        goto out_free;
                }
 
-               rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__RELABELFROM, NULL, NULL);
-               if (rc)
+               if (!fscontext) {
+                       rc = may_context_mount_sb_relabel(sid, sbsec, tsec);
+                       if (rc)
+                               goto out_free;
+                       sbsec->sid = sid;
+               } else {
+                       rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
+                       if (rc)
+                               goto out_free;
+               }
+               sbsec->mntpoint_sid = sid;
+
+               sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
+       }
+
+       if (rootcontext) {
+               struct inode *inode = sb->s_root->d_inode;
+               struct inode_security_struct *isec = inode->i_security;
+               rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid);
+               if (rc) {
+                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                              "(%s) failed for (dev %s, type %s) errno=%d\n",
+                              rootcontext, sb->s_id, name, rc);
                        goto out_free;
+               }
 
-               rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__RELABELTO, NULL, NULL);
+               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
                if (rc)
                        goto out_free;
 
-               sbsec->sid = sid;
-
-               if (seen & Opt_context)
-                       sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
+               isec->sid = sid;
+               isec->initialized = 1;
        }
 
        if (defcontext) {
@@ -481,13 +570,7 @@ static int try_context_mount(struct super_block *sb, void *data)
                if (sid == sbsec->def_sid)
                        goto out_free;
 
-               rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__RELABELFROM, NULL, NULL);
-               if (rc)
-                       goto out_free;
-
-               rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                                 FILESYSTEM__ASSOCIATE, NULL, NULL);
+               rc = may_context_mount_inode_relabel(sid, sbsec, tsec);
                if (rc)
                        goto out_free;
 
@@ -498,6 +581,8 @@ out_free:
        if (alloc) {
                kfree(context);
                kfree(defcontext);
+               kfree(fscontext);
+               kfree(rootcontext);
        }
 out:
        return rc;
@@ -510,7 +595,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
        struct inode *inode = root->d_inode;
        int rc = 0;
 
-       down(&sbsec->sem);
+       mutex_lock(&sbsec->lock);
        if (sbsec->initialized)
                goto out;
 
@@ -595,7 +680,8 @@ next_inode:
                spin_unlock(&sbsec->isec_lock);
                inode = igrab(inode);
                if (inode) {
-                       inode_doinit(inode);
+                       if (!IS_PRIVATE (inode))
+                               inode_doinit(inode);
                        iput(inode);
                }
                spin_lock(&sbsec->isec_lock);
@@ -604,7 +690,7 @@ next_inode:
        }
        spin_unlock(&sbsec->isec_lock);
 out:
-       up(&sbsec->sem);
+       mutex_unlock(&sbsec->lock);
        return rc;
 }
 
@@ -631,33 +717,54 @@ static inline u16 inode_mode_to_security_class(umode_t mode)
        return SECCLASS_FILE;
 }
 
+static inline int default_protocol_stream(int protocol)
+{
+       return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
+}
+
+static inline int default_protocol_dgram(int protocol)
+{
+       return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
+}
+
 static inline u16 socket_type_to_security_class(int family, int type, int protocol)
 {
        switch (family) {
        case PF_UNIX:
                switch (type) {
                case SOCK_STREAM:
+               case SOCK_SEQPACKET:
                        return SECCLASS_UNIX_STREAM_SOCKET;
                case SOCK_DGRAM:
                        return SECCLASS_UNIX_DGRAM_SOCKET;
                }
+               break;
        case PF_INET:
        case PF_INET6:
                switch (type) {
                case SOCK_STREAM:
-                       return SECCLASS_TCP_SOCKET;
+                       if (default_protocol_stream(protocol))
+                               return SECCLASS_TCP_SOCKET;
+                       else
+                               return SECCLASS_RAWIP_SOCKET;
                case SOCK_DGRAM:
-                       return SECCLASS_UDP_SOCKET;
-               case SOCK_RAW:
+                       if (default_protocol_dgram(protocol))
+                               return SECCLASS_UDP_SOCKET;
+                       else
+                               return SECCLASS_RAWIP_SOCKET;
+               case SOCK_DCCP:
+                       return SECCLASS_DCCP_SOCKET;
+               default:
                        return SECCLASS_RAWIP_SOCKET;
                }
+               break;
        case PF_NETLINK:
                switch (protocol) {
                case NETLINK_ROUTE:
                        return SECCLASS_NETLINK_ROUTE_SOCKET;
                case NETLINK_FIREWALL:
                        return SECCLASS_NETLINK_FIREWALL_SOCKET;
-               case NETLINK_TCPDIAG:
+               case NETLINK_INET_DIAG:
                        return SECCLASS_NETLINK_TCPDIAG_SOCKET;
                case NETLINK_NFLOG:
                        return SECCLASS_NETLINK_NFLOG_SOCKET;
@@ -671,6 +778,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                        return SECCLASS_NETLINK_IP6FW_SOCKET;
                case NETLINK_DNRTMSG:
                        return SECCLASS_NETLINK_DNRT_SOCKET;
+               case NETLINK_KOBJECT_UEVENT:
+                       return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
                default:
                        return SECCLASS_NETLINK_SOCKET;
                }
@@ -678,6 +787,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                return SECCLASS_PACKET_SOCKET;
        case PF_KEY:
                return SECCLASS_KEY_SOCKET;
+       case PF_APPLETALK:
+               return SECCLASS_APPLETALK_SOCKET;
        }
 
        return SECCLASS_SOCKET;
@@ -735,15 +846,13 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
        char *context = NULL;
        unsigned len = 0;
        int rc = 0;
-       int hold_sem = 0;
 
        if (isec->initialized)
                goto out;
 
-       down(&isec->sem);
-       hold_sem = 1;
+       mutex_lock(&isec->lock);
        if (isec->initialized)
-               goto out;
+               goto out_unlock;
 
        sbsec = inode->i_sb->s_security;
        if (!sbsec->initialized) {
@@ -754,7 +863,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                if (list_empty(&isec->list))
                        list_add(&isec->list, &sbsec->isec_head);
                spin_unlock(&sbsec->isec_lock);
-               goto out;
+               goto out_unlock;
        }
 
        switch (sbsec->behavior) {
@@ -777,7 +886,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        printk(KERN_WARNING "%s:  no dentry for dev=%s "
                               "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
                               inode->i_ino);
-                       goto out;
+                       goto out_unlock;
                }
 
                len = INITCONTEXTLEN;
@@ -785,7 +894,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
-                       goto out;
+                       goto out_unlock;
                }
                rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
                                           context, len);
@@ -795,7 +904,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                                   NULL, 0);
                        if (rc < 0) {
                                dput(dentry);
-                               goto out;
+                               goto out_unlock;
                        }
                        kfree(context);
                        len = rc;
@@ -803,7 +912,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
-                               goto out;
+                               goto out_unlock;
                        }
                        rc = inode->i_op->getxattr(dentry,
                                                   XATTR_NAME_SELINUX,
@@ -816,20 +925,23 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                       "%d for dev=%s ino=%ld\n", __FUNCTION__,
                                       -rc, inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
-                               goto out;
+                               goto out_unlock;
                        }
                        /* Map ENODATA to the default file SID */
                        sid = sbsec->def_sid;
                        rc = 0;
                } else {
-                       rc = security_context_to_sid(context, rc, &sid);
+                       rc = security_context_to_sid_default(context, rc, &sid,
+                                                            sbsec->def_sid);
                        if (rc) {
                                printk(KERN_WARNING "%s:  context_to_sid(%s) "
                                       "returned %d for dev=%s ino=%ld\n",
                                       __FUNCTION__, context, -rc,
                                       inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
-                               goto out;
+                               /* Leave with the unlabeled SID */
+                               rc = 0;
+                               break;
                        }
                }
                kfree(context);
@@ -849,11 +961,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                             isec->sclass,
                                             &sid);
                if (rc)
-                       goto out;
+                       goto out_unlock;
                isec->sid = sid;
                break;
+       case SECURITY_FS_USE_MNTPOINT:
+               isec->sid = sbsec->mntpoint_sid;
+               break;
        default:
-               /* Default to the fs SID. */
+               /* Default to the fs superblock SID. */
                isec->sid = sbsec->sid;
 
                if (sbsec->proc) {
@@ -864,7 +979,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                                          isec->sclass,
                                                          &sid);
                                if (rc)
-                                       goto out;
+                                       goto out_unlock;
                                isec->sid = sid;
                        }
                }
@@ -873,22 +988,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
        isec->initialized = 1;
 
+out_unlock:
+       mutex_unlock(&isec->lock);
 out:
-       if (inode->i_sock) {
-               struct socket *sock = SOCKET_I(inode);
-               if (sock->sk) {
-                       isec->sclass = socket_type_to_security_class(sock->sk->sk_family,
-                                                                    sock->sk->sk_type,
-                                                                    sock->sk->sk_protocol);
-               } else {
-                       isec->sclass = SECCLASS_SOCKET;
-               }
-       } else {
+       if (isec->sclass == SECCLASS_FILE)
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-       }
-
-       if (hold_sem)
-               up(&isec->sem);
        return rc;
 }
 
@@ -921,21 +1025,21 @@ static inline u32 signal_to_av(int sig)
 
 /* Check permission betweeen a pair of tasks, e.g. signal checks,
    fork check, ptrace check, etc. */
-int task_has_perm(struct task_struct *tsk1,
-                 struct task_struct *tsk2,
-                 u32 perms)
+static int task_has_perm(struct task_struct *tsk1,
+                        struct task_struct *tsk2,
+                        u32 perms)
 {
        struct task_security_struct *tsec1, *tsec2;
 
        tsec1 = tsk1->security;
        tsec2 = tsk2->security;
        return avc_has_perm(tsec1->sid, tsec2->sid,
-                           SECCLASS_PROCESS, perms, &tsec2->avcr, NULL);
+                           SECCLASS_PROCESS, perms, NULL);
 }
 
 /* Check whether a task is allowed to use a capability. */
-int task_has_capability(struct task_struct *tsk,
-                       int cap)
+static int task_has_capability(struct task_struct *tsk,
+                              int cap)
 {
        struct task_security_struct *tsec;
        struct avc_audit_data ad;
@@ -947,31 +1051,28 @@ int task_has_capability(struct task_struct *tsk,
        ad.u.cap = cap;
 
        return avc_has_perm(tsec->sid, tsec->sid,
-                           SECCLASS_CAPABILITY, CAP_TO_MASK(cap), NULL, &ad);
+                           SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad);
 }
 
 /* Check whether a task is allowed to use a system operation. */
-int task_has_system(struct task_struct *tsk,
-                   u32 perms)
+static int task_has_system(struct task_struct *tsk,
+                          u32 perms)
 {
        struct task_security_struct *tsec;
 
        tsec = tsk->security;
 
        return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
-                           SECCLASS_SYSTEM, perms, NULL, NULL);
+                           SECCLASS_SYSTEM, perms, NULL);
 }
 
 /* Check whether a task has a particular permission to an inode.
-   The 'aeref' parameter is optional and allows other AVC
-   entry references to be passed (e.g. the one in the struct file).
    The 'adp' parameter is optional and allows other audit
    data to be passed (e.g. the dentry). */
-int inode_has_perm(struct task_struct *tsk,
-                  struct inode *inode,
-                  u32 perms,
-                  struct avc_entry_ref *aeref,
-                  struct avc_audit_data *adp)
+static int inode_has_perm(struct task_struct *tsk,
+                         struct inode *inode,
+                         u32 perms,
+                         struct avc_audit_data *adp)
 {
        struct task_security_struct *tsec;
        struct inode_security_struct *isec;
@@ -986,8 +1087,7 @@ int inode_has_perm(struct task_struct *tsk,
                ad.u.fs.inode = inode;
        }
 
-       return avc_has_perm(tsec->sid, isec->sid, isec->sclass,
-                           perms, aeref ? aeref : &isec->avcr, adp);
+       return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1003,7 +1103,7 @@ static inline int dentry_has_perm(struct task_struct *tsk,
        AVC_AUDIT_DATA_INIT(&ad,FS);
        ad.u.fs.mnt = mnt;
        ad.u.fs.dentry = dentry;
-       return inode_has_perm(tsk, inode, av, NULL, &ad);
+       return inode_has_perm(tsk, inode, av, &ad);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1014,14 +1114,14 @@ static inline int dentry_has_perm(struct task_struct *tsk,
    has the same SID as the process.  If av is zero, then
    access to the file is not checked, e.g. for cases
    where only the descriptor is affected like seek. */
-static inline int file_has_perm(struct task_struct *tsk,
+static int file_has_perm(struct task_struct *tsk,
                                struct file *file,
                                u32 av)
 {
        struct task_security_struct *tsec = tsk->security;
        struct file_security_struct *fsec = file->f_security;
-       struct vfsmount *mnt = file->f_vfsmnt;
-       struct dentry *dentry = file->f_dentry;
+       struct vfsmount *mnt = file->f_path.mnt;
+       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        struct avc_audit_data ad;
        int rc;
@@ -1034,14 +1134,14 @@ static inline int file_has_perm(struct task_struct *tsk,
                rc = avc_has_perm(tsec->sid, fsec->sid,
                                  SECCLASS_FD,
                                  FD__USE,
-                                 &fsec->avcr, &ad);
+                                 &ad);
                if (rc)
                        return rc;
        }
 
        /* av is zero if only checking access to the descriptor. */
        if (av)
-               return inode_has_perm(tsk, inode, av, &fsec->inode_avcr, &ad);
+               return inode_has_perm(tsk, inode, av, &ad);
 
        return 0;
 }
@@ -1067,7 +1167,7 @@ static int may_create(struct inode *dir,
 
        rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
-                         &dsec->avcr, &ad);
+                         &ad);
        if (rc)
                return rc;
 
@@ -1080,13 +1180,24 @@ static int may_create(struct inode *dir,
                        return rc;
        }
 
-       rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, NULL, &ad);
+       rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
        if (rc)
                return rc;
 
        return avc_has_perm(newsid, sbsec->sid,
                            SECCLASS_FILESYSTEM,
-                           FILESYSTEM__ASSOCIATE, NULL, &ad);
+                           FILESYSTEM__ASSOCIATE, &ad);
+}
+
+/* Check whether a task can create a key. */
+static int may_create_key(u32 ksid,
+                         struct task_struct *ctx)
+{
+       struct task_security_struct *tsec;
+
+       tsec = ctx->security;
+
+       return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
 }
 
 #define MAY_LINK   0
@@ -1114,8 +1225,7 @@ static int may_link(struct inode *dir,
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
-       rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
-                         av, &dsec->avcr, &ad);
+       rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
 
@@ -1134,8 +1244,7 @@ static int may_link(struct inode *dir,
                return 0;
        }
 
-       rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
-                         av, &isec->avcr, &ad);
+       rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad);
        return rc;
 }
 
@@ -1161,21 +1270,16 @@ static inline int may_rename(struct inode *old_dir,
 
        ad.u.fs.dentry = old_dentry;
        rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
-                         DIR__REMOVE_NAME | DIR__SEARCH,
-                         &old_dsec->avcr, &ad);
+                         DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
                return rc;
        rc = avc_has_perm(tsec->sid, old_isec->sid,
-                         old_isec->sclass,
-                         FILE__RENAME,
-                         &old_isec->avcr, &ad);
+                         old_isec->sclass, FILE__RENAME, &ad);
        if (rc)
                return rc;
        if (old_is_dir && new_dir != old_dir) {
                rc = avc_has_perm(tsec->sid, old_isec->sid,
-                                 old_isec->sclass,
-                                 DIR__REPARENT,
-                                 &old_isec->avcr, &ad);
+                                 old_isec->sclass, DIR__REPARENT, &ad);
                if (rc)
                        return rc;
        }
@@ -1184,8 +1288,7 @@ static inline int may_rename(struct inode *old_dir,
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (new_dentry->d_inode)
                av |= DIR__REMOVE_NAME;
-       rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR,
-                         av,&new_dsec->avcr, &ad);
+       rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
        if (rc)
                return rc;
        if (new_dentry->d_inode) {
@@ -1193,8 +1296,7 @@ static inline int may_rename(struct inode *old_dir,
                new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
                rc = avc_has_perm(tsec->sid, new_isec->sid,
                                  new_isec->sclass,
-                                 (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
-                                 &new_isec->avcr, &ad);
+                                 (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
                if (rc)
                        return rc;
        }
@@ -1203,10 +1305,10 @@ static inline int may_rename(struct inode *old_dir,
 }
 
 /* Check whether a task can perform a filesystem operation. */
-int superblock_has_perm(struct task_struct *tsk,
-                       struct super_block *sb,
-                       u32 perms,
-                       struct avc_audit_data *ad)
+static int superblock_has_perm(struct task_struct *tsk,
+                              struct super_block *sb,
+                              u32 perms,
+                              struct avc_audit_data *ad)
 {
        struct task_security_struct *tsec;
        struct superblock_security_struct *sbsec;
@@ -1214,7 +1316,7 @@ int superblock_has_perm(struct task_struct *tsk,
        tsec = tsk->security;
        sbsec = sb->s_security;
        return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
-                           perms, NULL, ad);
+                           perms, ad);
 }
 
 /* Convert a Linux mode and permission mask to an access vector. */
@@ -1262,121 +1364,17 @@ static inline u32 file_to_av(struct file *file)
        return av;
 }
 
-/* Set an inode's SID to a specified value. */
-int inode_security_set_sid(struct inode *inode, u32 sid)
-{
-       struct inode_security_struct *isec = inode->i_security;
-       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
-
-       if (!sbsec->initialized) {
-               /* Defer initialization to selinux_complete_init. */
-               return 0;
-       }
-
-       down(&isec->sem);
-       isec->sclass = inode_mode_to_security_class(inode->i_mode);
-       isec->sid = sid;
-       isec->initialized = 1;
-       up(&isec->sem);
-       return 0;
-}
-
-/* Set the security attributes on a newly created file. */
-static int post_create(struct inode *dir,
-                      struct dentry *dentry)
-{
-
-       struct task_security_struct *tsec;
-       struct inode *inode;
-       struct inode_security_struct *dsec;
-       struct superblock_security_struct *sbsec;
-       u32 newsid;
-       char *context;
-       unsigned int len;
-       int rc;
-
-       tsec = current->security;
-       dsec = dir->i_security;
-       sbsec = dir->i_sb->s_security;
-
-       inode = dentry->d_inode;
-       if (!inode) {
-               /* Some file system types (e.g. NFS) may not instantiate
-                  a dentry for all create operations (e.g. symlink),
-                  so we have to check to see if the inode is non-NULL. */
-               printk(KERN_WARNING "post_create:  no inode, dir (dev=%s, "
-                      "ino=%ld)\n", dir->i_sb->s_id, dir->i_ino);
-               return 0;
-       }
-
-       if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
-               newsid = tsec->create_sid;
-       } else {
-               rc = security_transition_sid(tsec->sid, dsec->sid,
-                                            inode_mode_to_security_class(inode->i_mode),
-                                            &newsid);
-               if (rc) {
-                       printk(KERN_WARNING "post_create:  "
-                              "security_transition_sid failed, rc=%d (dev=%s "
-                              "ino=%ld)\n",
-                              -rc, inode->i_sb->s_id, inode->i_ino);
-                       return rc;
-               }
-       }
-
-       rc = inode_security_set_sid(inode, newsid);
-       if (rc) {
-               printk(KERN_WARNING "post_create:  inode_security_set_sid "
-                      "failed, rc=%d (dev=%s ino=%ld)\n",
-                      -rc, inode->i_sb->s_id, inode->i_ino);
-               return rc;
-       }
-
-       if (sbsec->behavior == SECURITY_FS_USE_XATTR &&
-           inode->i_op->setxattr) {
-               /* Use extended attributes. */
-               rc = security_sid_to_context(newsid, &context, &len);
-               if (rc) {
-                       printk(KERN_WARNING "post_create:  sid_to_context "
-                              "failed, rc=%d (dev=%s ino=%ld)\n",
-                              -rc, inode->i_sb->s_id, inode->i_ino);
-                       return rc;
-               }
-               down(&inode->i_sem);
-               rc = inode->i_op->setxattr(dentry,
-                                          XATTR_NAME_SELINUX,
-                                          context, len, 0);
-               up(&inode->i_sem);
-               kfree(context);
-               if (rc < 0) {
-                       printk(KERN_WARNING "post_create:  setxattr failed, "
-                              "rc=%d (dev=%s ino=%ld)\n",
-                              -rc, inode->i_sb->s_id, inode->i_ino);
-                       return rc;
-               }
-       }
-
-       return 0;
-}
-
-
 /* Hook functions begin here. */
 
 static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
 {
-       struct task_security_struct *psec = parent->security;
-       struct task_security_struct *csec = child->security;
        int rc;
 
        rc = secondary_ops->ptrace(parent,child);
        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 (!rc)
-               csec->ptrace_sid = psec->sid;
-       return rc;
+       return task_has_perm(parent, child, PROCESS__PTRACE);
 }
 
 static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
@@ -1406,12 +1404,6 @@ 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)
 {
-       int error;
-
-       error = task_has_perm(current, target, PROCESS__SETCAP);
-       if (error)
-               return;
-
        secondary_ops->capset_set(target, effective, inheritable, permitted);
 }
 
@@ -1451,7 +1443,7 @@ static int selinux_sysctl(ctl_table *table, int op)
         * a bad coupling between this module and sysctl.c */
        if(op == 001) {
                error = avc_has_perm(tsec->sid, tsid,
-                                    SECCLASS_DIR, DIR__SEARCH, NULL, NULL);
+                                    SECCLASS_DIR, DIR__SEARCH, NULL);
        } else {
                av = 0;
                if (op & 004)
@@ -1460,7 +1452,7 @@ static int selinux_sysctl(ctl_table *table, int op)
                        av |= FILE__WRITE;
                if (av)
                        error = avc_has_perm(tsec->sid, tsid,
-                                            SECCLASS_FILE, av, NULL, NULL);
+                                            SECCLASS_FILE, av, NULL);
         }
 
        return error;
@@ -1497,9 +1489,9 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
        return rc;
 }
 
-static int selinux_quota_on(struct file *f)
+static int selinux_quota_on(struct dentry *dentry)
 {
-       return file_has_perm(current, f, FILE__QUOTAON);
+       return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1537,70 +1529,29 @@ static int selinux_syslog(int type)
  * mapping. 0 means there is enough memory for the allocation to
  * succeed and -ENOMEM implies there is not.
  *
- * We currently support three overcommit policies, which are set via the
- * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-accounting
+ * Note that secondary_ops->capable and task_has_perm_noaudit return 0
+ * if the capability is granted, but __vm_enough_memory requires 1 if
+ * the capability is granted.
  *
- * Strict overcommit modes added 2002 Feb 26 by Alan Cox.
- * Additional code 2002 Jul 20 by Robert Love.
+ * Do not audit the selinux permission check, as this is applied to all
+ * processes that allocate mappings.
  */
 static int selinux_vm_enough_memory(long pages)
 {
-       unsigned long free, allowed;
-       int rc;
+       int rc, cap_sys_admin = 0;
        struct task_security_struct *tsec = current->security;
 
-       vm_acct_memory(pages);
-
-        /*
-        * Sometimes we want to use more memory than we have
-        */
-       if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
-               return 0;
-
-       if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
-               free = get_page_cache_size();
-               free += nr_free_pages();
-               free += nr_swap_pages;
-
-               /*
-                * Any slabs which are created with the
-                * SLAB_RECLAIM_ACCOUNT flag claim to have contents
-                * which are reclaimable, under pressure.  The dentry
-                * cache and most inode caches should fall into this
-                */
-               free += atomic_read(&slab_reclaim_pages);
-
-               /*
-                * Leave the last 3% for privileged processes.
-                * Don't audit the check, as it is applied to all processes
-                * that allocate mappings.
-                */
-               rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
-               if (!rc) {
-                       rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-                                                 SECCLASS_CAPABILITY,
-                                                 CAP_TO_MASK(CAP_SYS_ADMIN),
-                                                 NULL, NULL);
-               }
-               if (rc)
-                       free -= free / 32;
-
-               if (free > pages)
-                       return 0;
-               vm_unacct_memory(pages);
-               return -ENOMEM;
-       }
-
-       allowed = (totalram_pages - hugetlb_total_pages())
-               * sysctl_overcommit_ratio / 100;
-       allowed += total_swap_pages;
-
-       if (atomic_read(&vm_committed_space) < allowed)
-               return 0;
+       rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
+       if (rc == 0)
+               rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+                                       SECCLASS_CAPABILITY,
+                                       CAP_TO_MASK(CAP_SYS_ADMIN),
+                                       NULL);
 
-       vm_unacct_memory(pages);
+       if (rc == 0)
+               cap_sys_admin = 1;
 
-       return -ENOMEM;
+       return __vm_enough_memory(pages, cap_sys_admin);
 }
 
 /* binprm security operations */
@@ -1609,12 +1560,10 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
 {
        struct bprm_security_struct *bsec;
 
-       bsec = kmalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
+       bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
        if (!bsec)
                return -ENOMEM;
 
-       memset(bsec, 0, sizeof *bsec);
-       bsec->magic = SELINUX_MAGIC;
        bsec->bprm = bprm;
        bsec->sid = SECINITSID_UNLABELED;
        bsec->set = 0;
@@ -1626,7 +1575,7 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
 static int selinux_bprm_set_security(struct linux_binprm *bprm)
 {
        struct task_security_struct *tsec;
-       struct inode *inode = bprm->file->f_dentry->d_inode;
+       struct inode *inode = bprm->file->f_path.dentry->d_inode;
        struct inode_security_struct *isec;
        struct bprm_security_struct *bsec;
        u32 newsid;
@@ -1648,8 +1597,10 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        /* Default to the current task SID. */
        bsec->sid = tsec->sid;
 
-       /* Reset create SID on execve. */
+       /* Reset fs, key, and sock SIDs on execve. */
        tsec->create_sid = 0;
+       tsec->keycreate_sid = 0;
+       tsec->sockcreate_sid = 0;
 
        if (tsec->exec_sid) {
                newsid = tsec->exec_sid;
@@ -1664,30 +1615,26 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        }
 
        AVC_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.mnt = bprm->file->f_vfsmnt;
-       ad.u.fs.dentry = bprm->file->f_dentry;
+       ad.u.fs.mnt = bprm->file->f_path.mnt;
+       ad.u.fs.dentry = bprm->file->f_path.dentry;
 
-       if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+       if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                newsid = tsec->sid;
 
         if (tsec->sid == newsid) {
                rc = avc_has_perm(tsec->sid, isec->sid,
-                                 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS,
-                                 &isec->avcr, &ad);
+                                 SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
                if (rc)
                        return rc;
        } else {
                /* Check permissions for the transition. */
                rc = avc_has_perm(tsec->sid, newsid,
-                                 SECCLASS_PROCESS, PROCESS__TRANSITION,
-                                 NULL,
-                                 &ad);
+                                 SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
                if (rc)
                        return rc;
 
                rc = avc_has_perm(newsid, isec->sid,
-                                 SECCLASS_FILE, FILE__ENTRYPOINT,
-                                 &isec->avcr, &ad);
+                                 SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
                if (rc)
                        return rc;
 
@@ -1719,7 +1666,7 @@ static int selinux_bprm_secureexec (struct linux_binprm *bprm)
                   the two SIDs, i.e. ahp returns 0. */
                atsecure = avc_has_perm(tsec->osid, tsec->sid,
                                         SECCLASS_PROCESS,
-                                        PROCESS__NOATSECURE, NULL, NULL);
+                                        PROCESS__NOATSECURE, NULL);
        }
 
        return (atsecure || secondary_ops->bprm_secureexec(bprm));
@@ -1727,9 +1674,8 @@ static int selinux_bprm_secureexec (struct linux_binprm *bprm)
 
 static void selinux_bprm_free_security(struct linux_binprm *bprm)
 {
-       struct bprm_security_struct *bsec = bprm->security;
+       kfree(bprm->security);
        bprm->security = NULL;
-       kfree(bsec);
 }
 
 extern struct vfsmount *selinuxfs_mount;
@@ -1740,29 +1686,35 @@ static inline void flush_unauthorized_files(struct files_struct * files)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
-       struct tty_struct *tty = current->signal->tty;
+       struct tty_struct *tty;
+       struct fdtable *fdt;
        long j = -1;
+       int drop_tty = 0;
 
+       mutex_lock(&tty_mutex);
+       tty = get_current_tty();
        if (tty) {
                file_list_lock();
-               file = list_entry(tty->tty_files.next, typeof(*file), f_list);
+               file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
                if (file) {
                        /* Revalidate access to controlling tty.
                           Use inode_has_perm on the tty inode directly rather
                           than using file_has_perm, as this particular open
                           file may belong to another process and we are only
                           interested in the inode-based check here. */
-                       struct inode *inode = file->f_dentry->d_inode;
+                       struct inode *inode = file->f_path.dentry->d_inode;
                        if (inode_has_perm(current, inode,
-                                          FILE__READ | FILE__WRITE,
-                                          NULL, NULL)) {
-                               /* Reset controlling tty. */
-                               current->signal->tty = NULL;
-                               current->signal->tty_old_pgrp = 0;
+                                          FILE__READ | FILE__WRITE, NULL)) {
+                               drop_tty = 1;
                        }
                }
                file_list_unlock();
+
+               /* Reset controlling tty. */
+               if (drop_tty)
+                       proc_set_tty(current, NULL);
        }
+       mutex_unlock(&tty_mutex);
 
        /* Revalidate access to inherited open files. */
 
@@ -1775,9 +1727,10 @@ static inline void flush_unauthorized_files(struct files_struct * files)
 
                j++;
                i = j * __NFDBITS;
-               if (i >= files->max_fds || i >= files->max_fdset)
+               fdt = files_fdtable(files);
+               if (i >= fdt->max_fds)
                        break;
-               set = files->open_fds->fds_bits[j];
+               set = fdt->open_fds->fds_bits[j];
                if (!set)
                        continue;
                spin_unlock(&files->file_lock);
@@ -1798,10 +1751,11 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                                                continue;
                                        }
                                        if (devnull) {
-                                               atomic_inc(&devnull->f_count);
+                                               get_file(devnull);
                                        } else {
                                                devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
-                                               if (!devnull) {
+                                               if (IS_ERR(devnull)) {
+                                                       devnull = NULL;
                                                        put_unused_fd(fd);
                                                        fput(file);
                                                        continue;
@@ -1823,10 +1777,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
        struct task_security_struct *tsec;
        struct bprm_security_struct *bsec;
        u32 sid;
-       struct av_decision avd;
-       struct itimerval itimer;
-       struct rlimit *rlim, *initrlim;
-       int rc, i;
+       int rc;
 
        secondary_ops->bprm_apply_creds(bprm, unsafe);
 
@@ -1836,100 +1787,127 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
        sid = bsec->sid;
 
        tsec->osid = tsec->sid;
+       bsec->unsafe = 0;
        if (tsec->sid != sid) {
                /* Check for shared state.  If not ok, leave SID
                   unchanged and kill. */
                if (unsafe & LSM_UNSAFE_SHARE) {
-                       rc = avc_has_perm_noaudit(tsec->sid, sid,
-                                         SECCLASS_PROCESS, PROCESS__SHARE,
-                                         NULL, &avd);
+                       rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+                                       PROCESS__SHARE, NULL);
                        if (rc) {
-                               task_unlock(current);
-                               avc_audit(tsec->sid, sid, SECCLASS_PROCESS,
-                                   PROCESS__SHARE, &avd, rc, NULL);
-                               force_sig_specific(SIGKILL, current);
-                               goto lock_out;
+                               bsec->unsafe = 1;
+                               return;
                        }
                }
 
                /* 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_noaudit(tsec->ptrace_sid, sid,
-                                         SECCLASS_PROCESS, PROCESS__PTRACE,
-                                         NULL, &avd);
-                       if (!rc)
-                               tsec->sid = sid;
-                       task_unlock(current);
-                       avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS,
-                                 PROCESS__PTRACE, &avd, rc, NULL);
-                       if (rc) {
-                               force_sig_specific(SIGKILL, current);
-                               goto lock_out;
-                       }
-               } else {
-                       tsec->sid = sid;
-                       task_unlock(current);
-               }
-
-               /* Close files for which the new task SID is not authorized. */
-               flush_unauthorized_files(current->files);
-
-               /* Check whether the new SID can inherit signal state
-                  from the old SID.  If not, clear itimers to avoid
-                  subsequent signal generation and flush and unblock
-                  signals. This must occur _after_ the task SID has
-                  been updated so that any kill done after the flush
-                  will be checked against the new SID. */
-               rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-                                 PROCESS__SIGINH, NULL, NULL);
-               if (rc) {
-                       memset(&itimer, 0, sizeof itimer);
-                       for (i = 0; i < 3; i++)
-                               do_setitimer(i, &itimer, NULL);
-                       flush_signals(current);
-                       spin_lock_irq(&current->sighand->siglock);
-                       flush_signal_handlers(current, 1);
-                       sigemptyset(&current->blocked);
-                       recalc_sigpending();
-                       spin_unlock_irq(&current->sighand->siglock);
-               }
-
-               /* Check whether the new SID can inherit resource limits
-                  from the old SID.  If not, reset all soft limits to
-                  the lower of the current task's hard limit and the init
-                  task's soft limit.  Note that the setting of hard limits 
-                  (even to lower them) can be controlled by the setrlimit 
-                  check. The inclusion of the init task's soft limit into
-                  the computation is to avoid resetting soft limits higher
-                  than the default soft limit for cases where the default
-                  is lower than the hard limit, e.g. RLIMIT_CORE or 
-                  RLIMIT_STACK.*/
-               rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
-                                 PROCESS__RLIMITINH, NULL, NULL);
-               if (rc) {
-                       for (i = 0; i < RLIM_NLIMITS; i++) {
-                               rlim = current->rlim + i;
-                               initrlim = init_task.rlim+i;
-                               rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur);
+                       struct task_struct *t;
+
+                       rcu_read_lock();
+                       t = tracehook_tracer_task(current);
+                       if (unlikely(t == NULL))
+                               rcu_read_unlock();
+                       else {
+                               struct task_security_struct *sec = t->security;
+                               u32 ptsid = sec->sid;
+                               rcu_read_unlock();
+
+                               rc = avc_has_perm(ptsid, sid,
+                                                 SECCLASS_PROCESS,
+                                                 PROCESS__PTRACE, NULL);
+                               if (rc) {
+                                       bsec->unsafe = 1;
+                                       return;
+                               }
                        }
                }
-
-               /* Wake up the parent if it is waiting so that it can
-                  recheck wait permission to the new task SID. */
-               wake_up_interruptible(&current->parent->wait_chldexit);
-
-lock_out:
-               task_lock(current);
-               return;
+               tsec->sid = sid;
        }
 }
 
-/* superblock security operations */
-
-static int selinux_sb_alloc_security(struct super_block *sb)
+/*
+ * called after apply_creds without the task lock held
+ */
+static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
 {
-       return superblock_alloc_security(sb);
+       struct task_security_struct *tsec;
+       struct rlimit *rlim, *initrlim;
+       struct itimerval itimer;
+       struct bprm_security_struct *bsec;
+       int rc, i;
+
+       tsec = current->security;
+       bsec = bprm->security;
+
+       if (bsec->unsafe) {
+               force_sig_specific(SIGKILL, current);
+               return;
+       }
+       if (tsec->osid == tsec->sid)
+               return;
+
+       /* Close files for which the new task SID is not authorized. */
+       flush_unauthorized_files(current->files);
+
+       /* Check whether the new SID can inherit signal state
+          from the old SID.  If not, clear itimers to avoid
+          subsequent signal generation and flush and unblock
+          signals. This must occur _after_ the task SID has
+         been updated so that any kill done after the flush
+         will be checked against the new SID. */
+       rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
+                         PROCESS__SIGINH, NULL);
+       if (rc) {
+               memset(&itimer, 0, sizeof itimer);
+               for (i = 0; i < 3; i++)
+                       do_setitimer(i, &itimer, NULL);
+               flush_signals(current);
+               spin_lock_irq(&current->sighand->siglock);
+               flush_signal_handlers(current, 1);
+               sigemptyset(&current->blocked);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+
+       /* Check whether the new SID can inherit resource limits
+          from the old SID.  If not, reset all soft limits to
+          the lower of the current task's hard limit and the init
+          task's soft limit.  Note that the setting of hard limits
+          (even to lower them) can be controlled by the setrlimit
+          check. The inclusion of the init task's soft limit into
+          the computation is to avoid resetting soft limits higher
+          than the default soft limit for cases where the default
+          is lower than the hard limit, e.g. RLIMIT_CORE or
+          RLIMIT_STACK.*/
+       rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
+                         PROCESS__RLIMITINH, NULL);
+       if (rc) {
+               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);
+               }
+       }
+
+       /* Wake up the parent if it is waiting so that it can
+          recheck wait permission to the new task SID. */
+       wake_up_interruptible(&current->parent->signal->wait_chldexit);
+}
+
+/* superblock security operations */
+
+static int selinux_sb_alloc_security(struct super_block *sb)
+{
+       return superblock_alloc_security(sb);
 }
 
 static void selinux_sb_free_security(struct super_block *sb)
@@ -1949,7 +1927,8 @@ 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("defcontext=", sizeof("defcontext=")-1, option, len) ||
+               match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -1957,18 +1936,40 @@ static inline void take_option(char **to, char *from, int *first, int len)
        if (!*first) {
                **to = ',';
                *to += 1;
-       }
-       else
+       } else
                *first = 0;
        memcpy(*to, from, len);
        *to += 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
+               *first = 0;
+
+       while (current_size < len) {
+               if (*from != '"') {
+                       **to = *from;
+                       *to += 1;
+               }
+               from += 1;
+               current_size += 1;
+       }
+}
+
 static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
 {
        int fnosec, fsec, rc = 0;
        char *in_save, *in_curr, *in_end;
        char *sec_curr, *nosec_save, *nosec;
+       int open_quote = 0;
 
        in_curr = orig;
        sec_curr = copy;
@@ -1990,11 +1991,14 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
        in_save = in_end = orig;
 
        do {
-               if (*in_end == ',' || *in_end == '\0') {
+               if (*in_end == '"')
+                       open_quote = !open_quote;
+               if ((*in_end == ',' && open_quote == 0) ||
+                               *in_end == '\0') {
                        int len = in_end - in_curr;
 
                        if (selinux_option(in_curr, len))
-                               take_option(&sec_curr, in_curr, &fsec, len);
+                               take_selinux_option(&sec_curr, in_curr, &fsec, len);
                        else
                                take_option(&nosec, in_curr, &fnosec, len);
 
@@ -2002,7 +2006,8 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
                }
        } while (*in_end++);
 
-       copy_page(in_save, nosec_save);
+       strcpy(in_save, nosec_save);
+       free_page((unsigned long)nosec_save);
 out:
        return rc;
 }
@@ -2021,13 +2026,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
        return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
 }
 
-static int selinux_sb_statfs(struct super_block *sb)
+static int selinux_sb_statfs(struct dentry *dentry)
 {
        struct avc_audit_data ad;
 
        AVC_AUDIT_DATA_INIT(&ad,FS);
-       ad.u.fs.dentry = sb->s_root;
-       return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
+       ad.u.fs.dentry = dentry->d_sb->s_root;
+       return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
 static int selinux_mount(char * dev_name,
@@ -2074,14 +2079,71 @@ static void selinux_inode_free_security(struct inode *inode)
        inode_free_security(inode);
 }
 
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
+                                      char **name, void **value,
+                                      size_t *len)
 {
-       return may_create(dir, dentry, SECCLASS_FILE);
+       struct task_security_struct *tsec;
+       struct inode_security_struct *dsec;
+       struct superblock_security_struct *sbsec;
+       u32 newsid, clen;
+       int rc;
+       char *namep = NULL, *context;
+
+       tsec = current->security;
+       dsec = dir->i_security;
+       sbsec = dir->i_sb->s_security;
+
+       if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+               newsid = tsec->create_sid;
+       } else {
+               rc = security_transition_sid(tsec->sid, dsec->sid,
+                                            inode_mode_to_security_class(inode->i_mode),
+                                            &newsid);
+               if (rc) {
+                       printk(KERN_WARNING "%s:  "
+                              "security_transition_sid failed, rc=%d (dev=%s "
+                              "ino=%ld)\n",
+                              __FUNCTION__,
+                              -rc, inode->i_sb->s_id, inode->i_ino);
+                       return rc;
+               }
+       }
+
+       /* Possibly defer initialization to selinux_complete_init. */
+       if (sbsec->initialized) {
+               struct inode_security_struct *isec = inode->i_security;
+               isec->sclass = inode_mode_to_security_class(inode->i_mode);
+               isec->sid = newsid;
+               isec->initialized = 1;
+       }
+
+       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+               return -EOPNOTSUPP;
+
+       if (name) {
+               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
+               if (!namep)
+                       return -ENOMEM;
+               *name = namep;
+       }
+
+       if (value && len) {
+               rc = security_sid_to_context(newsid, &context, &clen);
+               if (rc) {
+                       kfree(namep);
+                       return rc;
+               }
+               *value = context;
+               *len = clen;
+       }
+
+       return 0;
 }
 
-static void selinux_inode_post_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
 {
-       post_create(dir, dentry);
+       return may_create(dir, dentry, SECCLASS_FILE);
 }
 
 static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
@@ -2094,11 +2156,6 @@ static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, stru
        return may_link(dir, old_dentry, MAY_LINK);
 }
 
-static void selinux_inode_post_link(struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry)
-{
-       return;
-}
-
 static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
 {
        int rc;
@@ -2114,21 +2171,11 @@ static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const
        return may_create(dir, dentry, SECCLASS_LNK_FILE);
 }
 
-static void selinux_inode_post_symlink(struct inode *dir, struct dentry *dentry, const char *name)
-{
-       post_create(dir, dentry);
-}
-
 static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
 {
        return may_create(dir, dentry, SECCLASS_DIR);
 }
 
-static void selinux_inode_post_mkdir(struct inode *dir, struct dentry *dentry, int mask)
-{
-       post_create(dir, dentry);
-}
-
 static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
 {
        return may_link(dir, dentry, MAY_RMDIR);
@@ -2145,23 +2192,12 @@ static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mod
        return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
 
-static void selinux_inode_post_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
-{
-       post_create(dir, dentry);
-}
-
 static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
                                 struct inode *new_inode, struct dentry *new_dentry)
 {
        return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }
 
-static void selinux_inode_post_rename(struct inode *old_inode, struct dentry *old_dentry,
-                                      struct inode *new_inode, struct dentry *new_dentry)
-{
-       return;
-}
-
 static int selinux_inode_readlink(struct dentry *dentry)
 {
        return dentry_has_perm(current, NULL, dentry, FILE__READ);
@@ -2192,7 +2228,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, NULL);
+                              file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2203,6 +2239,9 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
        if (rc)
                return rc;
 
+       if (iattr->ia_valid & ATTR_FORCE)
+               return 0;
+
        if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
                               ATTR_ATIME_SET | ATTR_MTIME_SET))
                return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
@@ -2243,12 +2282,14 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
        if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
+       if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+               return -EPERM;
+
        AVC_AUDIT_DATA_INIT(&ad,FS);
        ad.u.fs.dentry = dentry;
 
        rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
-                         FILE__RELABELFROM,
-                         &isec->avcr, &ad);
+                         FILE__RELABELFROM, &ad);
        if (rc)
                return rc;
 
@@ -2257,7 +2298,12 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                return rc;
 
        rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
-                         FILE__RELABELTO, NULL, &ad);
+                         FILE__RELABELTO, &ad);
+       if (rc)
+               return rc;
+
+       rc = security_validate_transition(isec->sid, newsid, tsec->sid,
+                                         isec->sclass);
        if (rc)
                return rc;
 
@@ -2265,7 +2311,6 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                            sbsec->sid,
                            SECCLASS_FILESYSTEM,
                            FILESYSTEM__ASSOCIATE,
-                           NULL,
                            &ad);
 }
 
@@ -2295,12 +2340,6 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
 
 static int selinux_inode_getxattr (struct dentry *dentry, char *name)
 {
-       struct inode *inode = dentry->d_inode;
-       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
-
-       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
-               return -EOPNOTSUPP;
-
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
@@ -2331,40 +2370,31 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
        return -EACCES;
 }
 
-static int selinux_inode_getsecurity(struct dentry *dentry, const char *name, void *buffer, size_t size)
+static const char *selinux_inode_xattr_getsuffix(void)
 {
-       struct inode *inode = dentry->d_inode;
-       struct inode_security_struct *isec = inode->i_security;
-       char *context;
-       unsigned len;
-       int rc;
+      return XATTR_SELINUX_SUFFIX;
+}
 
-       /* Permission check handled by selinux_inode_getxattr hook.*/
+/*
+ * 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.
+ *
+ * Permission check is handled by selinux_inode_getxattr hook.
+ */
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+{
+       struct inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
-       rc = security_sid_to_context(isec->sid, &context, &len);
-       if (rc)
-               return rc;
-
-       if (!buffer || !size) {
-               kfree(context);
-               return len;
-       }
-       if (size < len) {
-               kfree(context);
-               return -ERANGE;
-       }
-       memcpy(buffer, context, len);
-       kfree(context);
-       return len;
+       return selinux_getsecurity(isec->sid, buffer, size);
 }
 
-static int selinux_inode_setsecurity(struct dentry *dentry, const char *name,
+static int selinux_inode_setsecurity(struct inode *inode, 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;
        u32 newsid;
        int rc;
@@ -2383,10 +2413,10 @@ static int selinux_inode_setsecurity(struct dentry *dentry, const char *name,
        return 0;
 }
 
-static int selinux_inode_listsecurity(struct dentry *dentry, char *buffer)
+static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
 {
        const int len = sizeof(XATTR_NAME_SELINUX);
-       if (buffer)
+       if (buffer && len <= buffer_size)
                memcpy(buffer, XATTR_NAME_SELINUX, len);
        return len;
 }
@@ -2395,7 +2425,8 @@ static int selinux_inode_listsecurity(struct dentry *dentry, char *buffer)
 
 static int selinux_file_permission(struct file *file, int mask)
 {
-       struct inode *inode = file->f_dentry->d_inode;
+       int rc;
+       struct inode *inode = file->f_path.dentry->d_inode;
 
        if (!mask) {
                /* No permission to check.  Existence test. */
@@ -2406,8 +2437,12 @@ static int selinux_file_permission(struct file *file, int mask)
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
 
-       return file_has_perm(current, file,
-                            file_mask_to_av(inode->i_mode, mask));
+       rc = file_has_perm(current, file,
+                          file_mask_to_av(inode->i_mode, mask));
+       if (rc)
+               return rc;
+
+       return selinux_netlbl_inode_permission(inode, mask);
 }
 
 static int selinux_file_alloc_security(struct file *file)
@@ -2468,6 +2503,17 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+       if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
+               /*
+                * We are making executable an anonymous mapping or a
+                * private file mapping that will also be writable.
+                * This has an additional check.
+                */
+               int rc = task_has_perm(current, current, PROCESS__EXECMEM);
+               if (rc)
+                       return rc;
+       }
+
        if (file) {
                /* read access is always possible with a mapping */
                u32 av = FILE__READ;
@@ -2484,27 +2530,60 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
        return 0;
 }
 
-static int selinux_file_mmap(struct file *file, unsigned long prot, unsigned long flags)
+static int selinux_file_mmap(struct file *file, unsigned long reqprot,
+                            unsigned long prot, unsigned long flags)
 {
        int rc;
 
-       rc = secondary_ops->file_mmap(file, prot, flags);
+       rc = secondary_ops->file_mmap(file, reqprot, prot, flags);
        if (rc)
                return rc;
 
+       if (selinux_checkreqprot)
+               prot = reqprot;
+
        return file_map_prot_check(file, prot,
                                   (flags & MAP_TYPE) == MAP_SHARED);
 }
 
 static int selinux_file_mprotect(struct vm_area_struct *vma,
+                                unsigned long reqprot,
                                 unsigned long prot)
 {
        int rc;
 
-       rc = secondary_ops->file_mprotect(vma, prot);
+       rc = secondary_ops->file_mprotect(vma, reqprot, prot);
        if (rc)
                return rc;
 
+       if (selinux_checkreqprot)
+               prot = reqprot;
+
+       if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
+               rc = 0;
+               if (vma->vm_start >= vma->vm_mm->start_brk &&
+                   vma->vm_end <= vma->vm_mm->brk) {
+                       rc = task_has_perm(current, current,
+                                          PROCESS__EXECHEAP);
+               } else if (!vma->vm_file &&
+                          vma->vm_start <= vma->vm_mm->start_stack &&
+                          vma->vm_end >= vma->vm_mm->start_stack) {
+                       rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+               } else if (vma->vm_file && vma->anon_vma) {
+                       /*
+                        * We are making executable a file mapping that has
+                        * had some COW done. Since pages might have been
+                        * written, check ability to execute the possibly
+                        * modified content.  This typically should only
+                        * occur for text relocations.
+                        */
+                       rc = file_has_perm(current, vma->vm_file,
+                                          FILE__EXECMOD);
+               }
+               if (rc)
+                       return rc;
+       }
+
        return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
 }
 
@@ -2520,7 +2599,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
 
        switch (cmd) {
                case F_SETFL:
-                       if (!file->f_dentry || !file->f_dentry->d_inode) {
+                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
                                err = -EINVAL;
                                break;
                        }
@@ -2546,7 +2625,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
                case F_SETLK64:
                case F_SETLKW64:
 #endif
-                       if (!file->f_dentry || !file->f_dentry->d_inode) {
+                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
                                err = -EINVAL;
                                break;
                        }
@@ -2570,8 +2649,7 @@ static int selinux_file_set_fowner(struct file *file)
 }
 
 static int selinux_file_send_sigiotask(struct task_struct *tsk,
-                                      struct fown_struct *fown,
-                                      int fd, int reason)
+                                      struct fown_struct *fown, int signum)
 {
         struct file *file;
        u32 perm;
@@ -2584,13 +2662,13 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
        tsec = tsk->security;
        fsec = file->f_security;
 
-       if (!fown->signum)
+       if (!signum)
                perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
        else
-               perm = signal_to_av(fown->signum);
+               perm = signal_to_av(signum);
 
        return avc_has_perm(fsec->fown_sid, tsec->sid,
-                           SECCLASS_PROCESS, perm, NULL, NULL);
+                           SECCLASS_PROCESS, perm, NULL);
 }
 
 static int selinux_file_receive(struct file *file)
@@ -2626,14 +2704,11 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->osid = tsec1->osid;
        tsec2->sid = tsec1->sid;
 
-       /* Retain the exec and create SIDs across fork */
+       /* Retain the exec, fs, key, and sock SIDs across fork */
        tsec2->exec_sid = tsec1->exec_sid;
        tsec2->create_sid = tsec1->create_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;
+       tsec2->keycreate_sid = tsec1->keycreate_sid;
+       tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
        return 0;
 }
@@ -2680,6 +2755,11 @@ static int selinux_task_getsid(struct task_struct *p)
        return task_has_perm(current, p, PROCESS__GETSESSION);
 }
 
+static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
+{
+       selinux_get_task_sid(p, secid);
+}
+
 static int selinux_task_setgroups(struct group_info *group_info)
 {
        /* See the comment for setuid above. */
@@ -2697,9 +2777,19 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
        return task_has_perm(current,p, PROCESS__SETSCHED);
 }
 
+static int selinux_task_setioprio(struct task_struct *p, int ioprio)
+{
+       return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
+static int selinux_task_getioprio(struct task_struct *p)
+{
+       return task_has_perm(current, p, PROCESS__GETSCHED);
+}
+
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
 {
-       struct rlimit *old_rlim = current->rlim + resource;
+       struct rlimit *old_rlim = current->signal->rlim + resource;
        int rc;
 
        rc = secondary_ops->task_setrlimit(resource, new_rlim);
@@ -2718,17 +2808,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim
 
 static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
 {
-       struct task_security_struct *tsec1, *tsec2;
-
-       tsec1 = current->security;
-       tsec2 = p->security;
-
-       /* No auditing from the setscheduler hook, since the runqueue lock
-          is held and the system will deadlock if we try to log an audit
-          message. */
-       return avc_has_perm_noaudit(tsec1->sid, tsec2->sid,
-                                   SECCLASS_PROCESS, PROCESS__SETSCHED,
-                                   &tsec2->avcr, NULL);
+       return task_has_perm(current, p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_getscheduler(struct task_struct *p)
@@ -2736,25 +2816,35 @@ static int selinux_task_getscheduler(struct task_struct *p)
        return task_has_perm(current, p, PROCESS__GETSCHED);
 }
 
-static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
+static int selinux_task_movememory(struct task_struct *p)
+{
+       return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
+static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
+                               int sig, u32 secid)
 {
        u32 perm;
        int rc;
+       struct task_security_struct *tsec;
 
-       rc = secondary_ops->task_kill(p, info, sig);
+       rc = secondary_ops->task_kill(p, info, sig, secid);
        if (rc)
                return rc;
 
-       if (info && ((unsigned long)info == 1 ||
-                    (unsigned long)info == 2 || SI_FROMKERNEL(info)))
+       if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
                return 0;
 
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
                perm = signal_to_av(sig);
-
-       return task_has_perm(current, p, perm);
+       tsec = p->security;
+       if (secid)
+               rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
+       else
+               rc = task_has_perm(current, p, perm);
+       return rc;
 }
 
 static int selinux_task_prctl(int option,
@@ -2801,10 +2891,9 @@ static void selinux_task_to_inode(struct task_struct *p,
        return;
 }
 
-#ifdef CONFIG_SECURITY_NETWORK
-
 /* Returns error only if unable to parse addresses */
-static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad)
+static int selinux_parse_skb_ipv4(struct sk_buff *skb,
+                       struct avc_audit_data *ad, u8 *proto)
 {
        int offset, ihlen, ret = -EINVAL;
        struct iphdr _iph, *ih;
@@ -2822,6 +2911,9 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad
        ad->u.net.v4info.daddr = ih->daddr;
        ret = 0;
 
+       if (proto)
+               *proto = ih->protocol;
+
        switch (ih->protocol) {
         case IPPROTO_TCP: {
                struct tcphdr _tcph, *th;
@@ -2855,6 +2947,22 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad
                break;
         }
 
+       case IPPROTO_DCCP: {
+               struct dccp_hdr _dccph, *dh;
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
+               offset += ihlen;
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+        }
+
         default:
                break;
         }
@@ -2865,7 +2973,8 @@ out:
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
 /* Returns error only if unable to parse addresses */
-static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad)
+static int selinux_parse_skb_ipv6(struct sk_buff *skb,
+                       struct avc_audit_data *ad, u8 *proto)
 {
        u8 nexthdr;
        int ret = -EINVAL, offset;
@@ -2882,11 +2991,13 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad
 
        nexthdr = ip6->nexthdr;
        offset += sizeof(_ipv6h);
-       offset = ipv6_skip_exthdr(skb, offset, &nexthdr,
-                                 skb->tail - skb->head - offset);
+       offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
        if (offset < 0)
                goto out;
 
+       if (proto)
+               *proto = nexthdr;
+
        switch (nexthdr) {
        case IPPROTO_TCP: {
                struct tcphdr _tcph, *th;
@@ -2912,6 +3023,18 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad
                break;
        }
 
+       case IPPROTO_DCCP: {
+               struct dccp_hdr _dccph, *dh;
+
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh == NULL)
+                       break;
+
+               ad->u.net.sport = dh->dccph_sport;
+               ad->u.net.dport = dh->dccph_dport;
+               break;
+        }
+
        /* includes fragments */
        default:
                break;
@@ -2923,13 +3046,13 @@ out:
 #endif /* IPV6 */
 
 static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
-                            char **addrp, int *len, int src)
+                            char **addrp, int *len, int src, u8 *proto)
 {
        int ret = 0;
 
        switch (ad->u.net.family) {
        case PF_INET:
-               ret = selinux_parse_skb_ipv4(skb, ad);
+               ret = selinux_parse_skb_ipv4(skb, ad, proto);
                if (ret || !addrp)
                        break;
                *len = 4;
@@ -2939,7 +3062,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        case PF_INET6:
-               ret = selinux_parse_skb_ipv6(skb, ad);
+               ret = selinux_parse_skb_ipv6(skb, ad, proto);
                if (ret || !addrp)
                        break;
                *len = 16;
@@ -2971,8 +3094,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
 
        AVC_AUDIT_DATA_INIT(&ad,NET);
        ad.u.net.sk = sock->sk;
-       err = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
-                          perms, &isec->avcr, &ad);
+       err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
 
 out:
        return err;
@@ -2983,36 +3105,45 @@ static int selinux_socket_create(int family, int type,
 {
        int err = 0;
        struct task_security_struct *tsec;
+       u32 newsid;
 
        if (kern)
                goto out;
 
        tsec = current->security;
-       err = avc_has_perm(tsec->sid, tsec->sid,
+       newsid = tsec->sockcreate_sid ? : tsec->sid;
+       err = avc_has_perm(tsec->sid, newsid,
                           socket_type_to_security_class(family, type,
-                          protocol), SOCKET__CREATE, NULL, NULL);
+                          protocol), SOCKET__CREATE, NULL);
 
 out:
        return err;
 }
 
-static void selinux_socket_post_create(struct socket *sock, int family,
-                                      int type, int protocol, int kern)
+static int selinux_socket_post_create(struct socket *sock, int family,
+                                     int type, int protocol, int kern)
 {
-       int err;
+       int err = 0;
        struct inode_security_struct *isec;
        struct task_security_struct *tsec;
+       struct sk_security_struct *sksec;
+       u32 newsid;
 
-       err = inode_doinit(SOCK_INODE(sock));
-       if (err < 0)
-               return;
        isec = SOCK_INODE(sock)->i_security;
 
        tsec = current->security;
+       newsid = tsec->sockcreate_sid ? : tsec->sid;
        isec->sclass = socket_type_to_security_class(family, type, protocol);
-       isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
+       isec->sid = kern ? SECINITSID_KERNEL : newsid;
+       isec->initialized = 1;
 
-       return;
+       if (sock->sk) {
+               sksec = sock->sk->sk_security;
+               sksec->sid = isec->sid;
+               err = selinux_netlbl_socket_post_create(sock);
+       }
+
+       return err;
 }
 
 /* Range of port numbers used to automatically bind.
@@ -3032,6 +3163,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
 
        /*
         * If PF_INET or PF_INET6, check name_bind permission for the port.
+        * Multiple address binding for SCTP is not supported yet: we just
+        * check the first address now.
         */
        family = sock->sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
@@ -3071,20 +3204,24 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        ad.u.net.family = family;
                        err = avc_has_perm(isec->sid, sid,
                                           isec->sclass,
-                                          SOCKET__NAME_BIND, NULL, &ad);
+                                          SOCKET__NAME_BIND, &ad);
                        if (err)
                                goto out;
                }
                
-               switch(sk->sk_protocol) {
-               case IPPROTO_TCP:
+               switch(isec->sclass) {
+               case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
                        
-               case IPPROTO_UDP:
+               case SECCLASS_UDP_SOCKET:
                        node_perm = UDP_SOCKET__NODE_BIND;
                        break;
-                       
+
+               case SECCLASS_DCCP_SOCKET:
+                       node_perm = DCCP_SOCKET__NODE_BIND;
+                       break;
+
                default:
                        node_perm = RAWIP_SOCKET__NODE_BIND;
                        break;
@@ -3104,7 +3241,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, NULL, &ad);
+                                  isec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3114,7 +3251,56 @@ out:
 
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
-       return socket_has_perm(current, sock, SOCKET__CONNECT);
+       struct inode_security_struct *isec;
+       int err;
+
+       err = socket_has_perm(current, sock, SOCKET__CONNECT);
+       if (err)
+               return err;
+
+       /*
+        * If a TCP or DCCP socket, check name_connect permission for the port.
+        */
+       isec = SOCK_INODE(sock)->i_security;
+       if (isec->sclass == SECCLASS_TCP_SOCKET ||
+           isec->sclass == SECCLASS_DCCP_SOCKET) {
+               struct sock *sk = sock->sk;
+               struct avc_audit_data ad;
+               struct sockaddr_in *addr4 = NULL;
+               struct sockaddr_in6 *addr6 = NULL;
+               unsigned short snum;
+               u32 sid, perm;
+
+               if (sk->sk_family == PF_INET) {
+                       addr4 = (struct sockaddr_in *)address;
+                       if (addrlen < sizeof(struct sockaddr_in))
+                               return -EINVAL;
+                       snum = ntohs(addr4->sin_port);
+               } else {
+                       addr6 = (struct sockaddr_in6 *)address;
+                       if (addrlen < SIN6_LEN_RFC2133)
+                               return -EINVAL;
+                       snum = ntohs(addr6->sin6_port);
+               }
+
+               err = security_port_sid(sk->sk_family, sk->sk_type,
+                                       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);
+               ad.u.net.dport = htons(snum);
+               ad.u.net.family = sk->sk_family;
+               err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+               if (err)
+                       goto out;
+       }
+
+out:
+       return err;
 }
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
@@ -3132,14 +3318,12 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        if (err)
                return err;
 
-       err = inode_doinit(SOCK_INODE(newsock));
-       if (err < 0)
-               return err;
        newisec = SOCK_INODE(newsock)->i_security;
 
        isec = SOCK_INODE(sock)->i_security;
        newisec->sclass = isec->sclass;
        newisec->sid = isec->sid;
+       newisec->initialized = 1;
 
        return 0;
 }
@@ -3147,7 +3331,13 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       return socket_has_perm(current, sock, SOCKET__WRITE);
+       int rc;
+
+       rc = socket_has_perm(current, sock, SOCKET__WRITE);
+       if (rc)
+               return rc;
+
+       return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -3168,7 +3358,13 @@ static int selinux_socket_getpeername(struct socket *sock)
 
 static int selinux_socket_setsockopt(struct socket *sock,int level,int optname)
 {
-       return socket_has_perm(current, sock, SOCKET__SETOPT);
+       int err;
+
+       err = socket_has_perm(current, sock, SOCKET__SETOPT);
+       if (err)
+               return err;
+
+       return selinux_netlbl_socket_setsockopt(sock, level, optname);
 }
 
 static int selinux_socket_getsockopt(struct socket *sock, int level,
@@ -3204,8 +3400,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
 
        err = avc_has_perm(isec->sid, other_isec->sid,
                           isec->sclass,
-                          UNIX_STREAM_SOCKET__CONNECTTO,
-                          &other_isec->avcr, &ad);
+                          UNIX_STREAM_SOCKET__CONNECTTO, &ad);
        if (err)
                return err;
 
@@ -3216,8 +3411,9 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        /* server child socket */
        ssec = newsk->sk_security;
        ssec->peer_sid = isec->sid;
-       
-       return 0;
+       err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid);
+
+       return err;
 }
 
 static int selinux_socket_unix_may_send(struct socket *sock,
@@ -3235,36 +3431,21 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass,
-                          SOCKET__SENDTO,
-                          &other_isec->avcr, &ad);
+                          isec->sclass, SOCKET__SENDTO, &ad);
        if (err)
                return err;
 
        return 0;
 }
 
-static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+               struct avc_audit_data *ad, u16 family, char *addrp, int len)
 {
-       u16 family;
-       char *addrp;
-       int len, err = 0;
-       u32 netif_perm, node_perm, node_sid, recv_perm = 0;
-       u32 sock_sid = 0;
-       u16 sock_class = 0;
+       int err = 0;
+       u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0;
        struct socket *sock;
-       struct net_device *dev;
-       struct sel_netif *netif;
-       struct netif_security_struct *nsec;
-       struct avc_audit_data ad;
-
-       family = sk->sk_family;
-       if (family != PF_INET && family != PF_INET6)
-               goto out;
-
-       /* Handle mapped IPv4 packets arriving via IPv6 sockets */
-       if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
-               family = PF_INET;
+       u16 sock_class = 0;
+       u32 sock_sid = 0;
 
        read_lock_bh(&sk->sk_callback_lock);
        sock = sk->sk_socket;
@@ -3282,17 +3463,12 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!sock_sid)
                goto out;
 
-       dev = skb->dev;
-       if (!dev)
+       if (!skb->dev)
                goto out;
 
-       netif = sel_netif_lookup(dev);
-       if (IS_ERR(netif)) {
-               err = PTR_ERR(netif);
+       err = sel_netif_sids(skb->dev, &if_sid, NULL);
+       if (err)
                goto out;
-       }
-       
-       nsec = &netif->nsec;
 
        switch (sock_class) {
        case SECCLASS_UDP_SOCKET:
@@ -3306,73 +3482,114 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                node_perm = NODE__TCP_RECV;
                recv_perm = TCP_SOCKET__RECV_MSG;
                break;
-       
+
+       case SECCLASS_DCCP_SOCKET:
+               netif_perm = NETIF__DCCP_RECV;
+               node_perm = NODE__DCCP_RECV;
+               recv_perm = DCCP_SOCKET__RECV_MSG;
+               break;
+
        default:
                netif_perm = NETIF__RAWIP_RECV;
                node_perm = NODE__RAWIP_RECV;
                break;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = dev->name;
-       ad.u.net.family = family;
-
-       err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
-       if (err) {
-               sel_netif_put(netif);
-               goto out;
-       }
-
-       err = avc_has_perm(sock_sid, nsec->if_sid, SECCLASS_NETIF,
-                          netif_perm, &nsec->avcr, &ad);
-       sel_netif_put(netif);
+       err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
        if (err)
                goto out;
        
-       /* Fixme: this lookup is inefficient */
        err = security_node_sid(family, addrp, len, &node_sid);
        if (err)
                goto out;
        
-       err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad);
+       err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad);
        if (err)
                goto out;
 
        if (recv_perm) {
                u32 port_sid;
 
-               /* Fixme: make this more efficient */
                err = security_port_sid(sk->sk_family, sk->sk_type,
-                                       sk->sk_protocol, ntohs(ad.u.net.sport),
+                                       sk->sk_protocol, ntohs(ad->u.net.sport),
                                        &port_sid);
                if (err)
                        goto out;
 
-               err = avc_has_perm(sock_sid, port_sid, sock_class,
-                                  recv_perm, NULL, &ad);
+               err = avc_has_perm(sock_sid, port_sid,
+                                  sock_class, recv_perm, ad);
        }
+
+out:
+       return err;
+}
+
+static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       u16 family;
+       char *addrp;
+       int len, err = 0;
+       struct avc_audit_data ad;
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       family = sk->sk_family;
+       if (family != PF_INET && family != PF_INET6)
+               goto out;
+
+       /* Handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+               family = PF_INET;
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]";
+       ad.u.net.family = family;
+
+       err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL);
+       if (err)
+               goto out;
+
+       if (selinux_compat_net)
+               err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family,
+                                                 addrp, len);
+       else
+               err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
+                                  PACKET__RECV, &ad);
+       if (err)
+               goto out;
+
+       err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad);
+       if (err)
+               goto out;
+
+       err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
 out:   
        return err;
 }
 
-static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
-                                    int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
+                                           int __user *optlen, unsigned len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
+       u32 peer_sid = SECSID_NULL;
 
        isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
+
+       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+           isec->sclass == SECCLASS_TCP_SOCKET) {
+               ssec = sock->sk->sk_security;
+               peer_sid = ssec->peer_sid;
+       }
+       if (peer_sid == SECSID_NULL) {
                err = -ENOPROTOOPT;
                goto out;
        }
 
-       ssec = sock->sk->sk_security;
-       
-       err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
+       err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
+
        if (err)
                goto out;
 
@@ -3393,7 +3610,26 @@ out:
        return err;
 }
 
-static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
+static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+{
+       u32 peer_secid = SECSID_NULL;
+       int err = 0;
+
+       if (sock && sock->sk->sk_family == PF_UNIX)
+               selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+       else if (skb)
+               security_skb_extlbl_sid(skb,
+                                       SECINITSID_UNLABELED,
+                                       &peer_secid);
+
+       if (peer_secid == SECSID_NULL)
+               err = -EINVAL;
+       *secid = peer_secid;
+
+       return err;
+}
+
+static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        return sk_alloc_security(sk, family, priority);
 }
@@ -3403,6 +3639,95 @@ static void selinux_sk_free_security(struct sock *sk)
        sk_free_security(sk);
 }
 
+static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
+{
+       struct sk_security_struct *ssec = sk->sk_security;
+       struct sk_security_struct *newssec = newsk->sk_security;
+
+       newssec->sid = ssec->sid;
+       newssec->peer_sid = ssec->peer_sid;
+
+       selinux_netlbl_sk_security_clone(ssec, newssec);
+}
+
+static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
+{
+       if (!sk)
+               *secid = SECINITSID_ANY_SOCKET;
+       else {
+               struct sk_security_struct *sksec = sk->sk_security;
+
+               *secid = sksec->sid;
+       }
+}
+
+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;
+
+       if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
+           sk->sk_family == PF_UNIX)
+               isec->sid = sksec->sid;
+
+       selinux_netlbl_sock_graft(sk, parent);
+}
+
+static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+                                    struct request_sock *req)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       int err;
+       u32 newsid;
+       u32 peersid;
+
+       security_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid);
+       if (peersid == SECSID_NULL) {
+               req->secid = sksec->sid;
+               req->peer_secid = SECSID_NULL;
+               return 0;
+       }
+
+       err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
+       if (err)
+               return err;
+
+       req->secid = newsid;
+       req->peer_secid = peersid;
+       return 0;
+}
+
+static void selinux_inet_csk_clone(struct sock *newsk,
+                                  const struct request_sock *req)
+{
+       struct sk_security_struct *newsksec = newsk->sk_security;
+
+       newsksec->sid = req->secid;
+       newsksec->peer_sid = req->peer_secid;
+       /* NOTE: Ideally, we should also get the isec->sid for the
+          new socket in sync, but we don't have the isec available yet.
+          So we will wait until sock_graft to do it, by which
+          time it will have been created and available. */
+
+       /* We don't need to take any sort of lock here as we are the only
+        * thread with access to newsksec */
+       selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
+}
+
+static void selinux_inet_conn_established(struct sock *sk,
+                               struct sk_buff *skb)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       security_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid);
+}
+
+static void selinux_req_classify_flow(const struct request_sock *req,
+                                     struct flowi *fl)
+{
+       fl->secid = req->secid;
+}
+
 static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
 {
        int err = 0;
@@ -3419,6 +3744,15 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        
        err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
+               if (err == -EINVAL) {
+                       audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
+                                 "SELinux:  unrecognized netlink message"
+                                 " type=%hu for sclass=%hu\n",
+                                 nlh->nlmsg_type, isec->sclass);
+                       if (!selinux_enforcing)
+                               err = 0;
+               }
+
                /* Ignore */
                if (err == -ENOENT)
                        err = 0;
@@ -3432,47 +3766,30 @@ out:
 
 #ifdef CONFIG_NETFILTER
 
-static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
-                                              struct sk_buff **pskb,
-                                              const struct net_device *in,
-                                              const struct net_device *out,
-                                              int (*okfn)(struct sk_buff *),
-                                              u16 family)
+static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
+                                           struct avc_audit_data *ad,
+                                           u16 family, char *addrp, int len)
 {
-       char *addrp;
-       int len, err = NF_ACCEPT;
-       u32 netif_perm, node_perm, node_sid, send_perm = 0;
-       struct sock *sk;
+       int err = 0;
+       u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
        struct socket *sock;
        struct inode *inode;
-       struct sel_netif *netif;
-       struct sk_buff *skb = *pskb;
-       struct netif_security_struct *nsec;
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
-       struct net_device *dev = (struct net_device *)out;
-       
-       sk = skb->sk;
-       if (!sk)
-               goto out;
-               
+
        sock = sk->sk_socket;
        if (!sock)
                goto out;
-               
+
        inode = SOCK_INODE(sock);
        if (!inode)
                goto out;
 
-       netif = sel_netif_lookup(dev);
-       if (IS_ERR(netif)) {
-               err = NF_DROP;
-               goto out;
-       }
-       
-       nsec = &netif->nsec;
        isec = inode->i_security;
        
+       err = sel_netif_sids(dev, &if_sid, NULL);
+       if (err)
+               goto out;
+
        switch (isec->sclass) {
        case SECCLASS_UDP_SOCKET:
                netif_perm = NETIF__UDP_SEND;
@@ -3485,62 +3802,94 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
                node_perm = NODE__TCP_SEND;
                send_perm = TCP_SOCKET__SEND_MSG;
                break;
-       
+
+       case SECCLASS_DCCP_SOCKET:
+               netif_perm = NETIF__DCCP_SEND;
+               node_perm = NODE__DCCP_SEND;
+               send_perm = DCCP_SOCKET__SEND_MSG;
+               break;
+
        default:
                netif_perm = NETIF__RAWIP_SEND;
                node_perm = NODE__RAWIP_SEND;
                break;
        }
 
-
-       AVC_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = dev->name;
-       ad.u.net.family = family;
-
-       err = selinux_parse_skb(skb, &ad, &addrp,
-                               &len, 0) ? NF_DROP : NF_ACCEPT;
-       if (err != NF_ACCEPT) {
-               sel_netif_put(netif);
-               goto out;
-       }
-
-       err = avc_has_perm(isec->sid, nsec->if_sid, SECCLASS_NETIF,
-                          netif_perm, &nsec->avcr, &ad) ? NF_DROP : NF_ACCEPT;
-       sel_netif_put(netif);
-       if (err != NF_ACCEPT)
+       err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
+       if (err)
                goto out;
                
-       /* Fixme: this lookup is inefficient */
-       err = security_node_sid(family, addrp, len,
-                               &node_sid) ? NF_DROP : NF_ACCEPT;
-       if (err != NF_ACCEPT)
+       err = security_node_sid(family, addrp, len, &node_sid);
+       if (err)
                goto out;
        
-       err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE,
-                          node_perm, NULL, &ad) ? NF_DROP : NF_ACCEPT;
-       if (err != NF_ACCEPT)
+       err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
+       if (err)
                goto out;
 
        if (send_perm) {
                u32 port_sid;
                
-               /* Fixme: make this more efficient */
                err = security_port_sid(sk->sk_family,
                                        sk->sk_type,
                                        sk->sk_protocol,
-                                       ntohs(ad.u.net.dport),
-                                       &port_sid) ? NF_DROP : NF_ACCEPT;
-               if (err != NF_ACCEPT)
+                                       ntohs(ad->u.net.dport),
+                                       &port_sid);
+               if (err)
                        goto out;
 
                err = avc_has_perm(isec->sid, port_sid, isec->sclass,
-                                  send_perm, NULL, &ad) ? NF_DROP : NF_ACCEPT;
+                                  send_perm, ad);
        }
-
 out:
        return err;
 }
 
+static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
+                                              struct sk_buff **pskb,
+                                              const struct net_device *in,
+                                              const struct net_device *out,
+                                              int (*okfn)(struct sk_buff *),
+                                              u16 family)
+{
+       char *addrp;
+       int len, err = 0;
+       struct sock *sk;
+       struct sk_buff *skb = *pskb;
+       struct avc_audit_data ad;
+       struct net_device *dev = (struct net_device *)out;
+       struct sk_security_struct *sksec;
+       u8 proto;
+
+       sk = skb->sk;
+       if (!sk)
+               goto out;
+
+       sksec = sk->sk_security;
+
+       AVC_AUDIT_DATA_INIT(&ad, NET);
+       ad.u.net.netif = dev->name;
+       ad.u.net.family = family;
+
+       err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto);
+       if (err)
+               goto out;
+
+       if (selinux_compat_net)
+               err = selinux_ip_postroute_last_compat(sk, dev, &ad,
+                                                      family, addrp, len);
+       else
+               err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
+                                  PACKET__SEND, &ad);
+
+       if (err)
+               goto out;
+
+       err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto);
+out:
+       return err ? NF_DROP : NF_ACCEPT;
+}
+
 static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
                                                struct sk_buff **pskb,
                                                const struct net_device *in,
@@ -3565,23 +3914,13 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
 
 #endif /* CONFIG_NETFILTER */
 
-#else
-
-static inline int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
-{
-       return 0;
-}
-
-#endif /* CONFIG_SECURITY_NETWORK */
-
 static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
-       int err = 0;
+       int err;
 
-       if (capable(CAP_NET_ADMIN))
-               cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
-       else
-               NETLINK_CB(skb).eff_cap = 0;
+       err = secondary_ops->netlink_send(sk, skb);
+       if (err)
+               return err;
 
        if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
                err = selinux_nlmsg_perm(sk, skb);
@@ -3589,11 +3928,20 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return err;
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb)
+static int selinux_netlink_recv(struct sk_buff *skb, int capability)
 {
-       if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
-               return -EPERM;
-       return 0;
+       int err;
+       struct avc_audit_data ad;
+
+       err = secondary_ops->netlink_recv(skb, capability);
+       if (err)
+               return err;
+
+       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       ad.u.cap = capability;
+
+       return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
+                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
 }
 
 static int ipc_alloc_security(struct task_struct *task,
@@ -3603,19 +3951,13 @@ static int ipc_alloc_security(struct task_struct *task,
        struct task_security_struct *tsec = task->security;
        struct ipc_security_struct *isec;
 
-       isec = kmalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
+       isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
-       memset(isec, 0, sizeof(struct ipc_security_struct));
-       isec->magic = SELINUX_MAGIC;
        isec->sclass = sclass;
        isec->ipc_perm = perm;
-       if (tsec) {
-               isec->sid = tsec->sid;
-       } else {
-               isec->sid = SECINITSID_UNLABELED;
-       }
+       isec->sid = tsec->sid;
        perm->security = isec;
 
        return 0;
@@ -3624,9 +3966,6 @@ static int ipc_alloc_security(struct task_struct *task,
 static void ipc_free_security(struct kern_ipc_perm *perm)
 {
        struct ipc_security_struct *isec = perm->security;
-       if (!isec || isec->magic != SELINUX_MAGIC)
-               return;
-
        perm->security = NULL;
        kfree(isec);
 }
@@ -3635,12 +3974,10 @@ static int msg_msg_alloc_security(struct msg_msg *msg)
 {
        struct msg_security_struct *msec;
 
-       msec = kmalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
+       msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
        if (!msec)
                return -ENOMEM;
 
-       memset(msec, 0, sizeof(struct msg_security_struct));
-       msec->magic = SELINUX_MAGIC;
        msec->msg = msg;
        msec->sid = SECINITSID_UNLABELED;
        msg->security = msec;
@@ -3651,15 +3988,13 @@ static int msg_msg_alloc_security(struct msg_msg *msg)
 static void msg_msg_free_security(struct msg_msg *msg)
 {
        struct msg_security_struct *msec = msg->security;
-       if (!msec || msec->magic != SELINUX_MAGIC)
-               return;
 
        msg->security = NULL;
        kfree(msec);
 }
 
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
-                       u16 sclass, u32 perms)
+                       u32 perms)
 {
        struct task_security_struct *tsec;
        struct ipc_security_struct *isec;
@@ -3671,8 +4006,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
        AVC_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = ipc_perms->key;
 
-       return avc_has_perm(tsec->sid, isec->sid, sclass,
-                           perms, &isec->avcr, &ad);
+       return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
 }
 
 static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -3704,7 +4038,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
-                         MSGQ__CREATE, &isec->avcr, &ad);
+                         MSGQ__CREATE, &ad);
        if (rc) {
                ipc_free_security(&msq->q_perm);
                return rc;
@@ -3730,7 +4064,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
        ad.u.ipc_id = msq->q_perm.key;
 
        return avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
-                           MSGQ__ASSOCIATE, &isec->avcr, &ad);
+                           MSGQ__ASSOCIATE, &ad);
 }
 
 static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
@@ -3757,7 +4091,7 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
                return 0;
        }
 
-       err = ipc_has_perm(&msq->q_perm, SECCLASS_MSGQ, perms);
+       err = ipc_has_perm(&msq->q_perm, perms);
        return err;
 }
 
@@ -3794,17 +4128,15 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
 
        /* Can this process write to the queue? */
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
-                         MSGQ__WRITE, &isec->avcr, &ad);
+                         MSGQ__WRITE, &ad);
        if (!rc)
                /* Can this process send the message */
                rc = avc_has_perm(tsec->sid, msec->sid,
-                                 SECCLASS_MSG, MSG__SEND,
-                                 &msec->avcr, &ad);
+                                 SECCLASS_MSG, MSG__SEND, &ad);
        if (!rc)
                /* Can the message be put in the queue? */
                rc = avc_has_perm(msec->sid, isec->sid,
-                                 SECCLASS_MSGQ, MSGQ__ENQUEUE,
-                                 &isec->avcr, &ad);
+                                 SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
 
        return rc;
 }
@@ -3827,12 +4159,10 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid,
-                         SECCLASS_MSGQ, MSGQ__READ,
-                         &isec->avcr, &ad);
+                         SECCLASS_MSGQ, MSGQ__READ, &ad);
        if (!rc)
                rc = avc_has_perm(tsec->sid, msec->sid,
-                                 SECCLASS_MSG, MSG__RECEIVE,
-                                 &msec->avcr, &ad);
+                                 SECCLASS_MSG, MSG__RECEIVE, &ad);
        return rc;
 }
 
@@ -3855,7 +4185,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
        ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
-                         SHM__CREATE, &isec->avcr, &ad);
+                         SHM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&shp->shm_perm);
                return rc;
@@ -3881,7 +4211,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
        ad.u.ipc_id = shp->shm_perm.key;
 
        return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
-                           SHM__ASSOCIATE, &isec->avcr, &ad);
+                           SHM__ASSOCIATE, &ad);
 }
 
 /* Note, at this point, shp is locked down */
@@ -3913,7 +4243,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
                return 0;
        }
 
-       err = ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms);
+       err = ipc_has_perm(&shp->shm_perm, perms);
        return err;
 }
 
@@ -3932,7 +4262,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
        else
                perms = SHM__READ | SHM__WRITE;
 
-       return ipc_has_perm(&shp->shm_perm, SECCLASS_SHM, perms);
+       return ipc_has_perm(&shp->shm_perm, perms);
 }
 
 /* Semaphore security operations */
@@ -3954,7 +4284,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
        ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
-                         SEM__CREATE, &isec->avcr, &ad);
+                         SEM__CREATE, &ad);
        if (rc) {
                ipc_free_security(&sma->sem_perm);
                return rc;
@@ -3980,7 +4310,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg)
        ad.u.ipc_id = sma->sem_perm.key;
 
        return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
-                           SEM__ASSOCIATE, &isec->avcr, &ad);
+                           SEM__ASSOCIATE, &ad);
 }
 
 /* Note, at this point, sma is locked down */
@@ -4021,7 +4351,7 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd)
                return 0;
        }
 
-       err = ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms);
+       err = ipc_has_perm(&sma->sem_perm, perms);
        return err;
 }
 
@@ -4035,18 +4365,13 @@ static int selinux_sem_semop(struct sem_array *sma,
        else
                perms = SEM__READ;
 
-       return ipc_has_perm(&sma->sem_perm, SECCLASS_SEM, perms);
+       return ipc_has_perm(&sma->sem_perm, perms);
 }
 
 static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 {
-       struct ipc_security_struct *isec = ipcp->security;
-       u16 sclass = SECCLASS_IPC;
        u32 av = 0;
 
-       if (isec && isec->magic == SELINUX_MAGIC)
-               sclass = isec->sclass;
-
        av = 0;
        if (flag & S_IRUGO)
                av |= IPC__UNIX_READ;
@@ -4056,11 +4381,11 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
        if (av == 0)
                return 0;
 
-       return ipc_has_perm(ipcp, sclass, av);
+       return ipc_has_perm(ipcp, av);
 }
 
 /* module stacking operations */
-int selinux_register_security (const char *name, struct security_operations *ops)
+static int selinux_register_security (const char *name, struct security_operations *ops)
 {
        if (secondary_ops != original_ops) {
                printk(KERN_INFO "%s:  There is already a secondary security "
@@ -4077,7 +4402,7 @@ int selinux_register_security (const char *name, struct security_operations *ops
        return 0;
 }
 
-int selinux_unregister_security (const char *name, struct security_operations *ops)
+static int selinux_unregister_security (const char *name, struct security_operations *ops)
 {
        if (ops != secondary_ops) {
                printk (KERN_INFO "%s:  trying to unregister a security module "
@@ -4100,8 +4425,7 @@ static int selinux_getprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
-       u32 sid, len;
-       char *context;
+       u32 sid;
        int error;
 
        if (current != p) {
@@ -4110,9 +4434,6 @@ static int selinux_getprocattr(struct task_struct *p,
                        return error;
        }
 
-       if (!size)
-               return -ERANGE;
-
        tsec = p->security;
 
        if (!strcmp(name, "current"))
@@ -4123,35 +4444,31 @@ static int selinux_getprocattr(struct task_struct *p,
                sid = tsec->exec_sid;
        else if (!strcmp(name, "fscreate"))
                sid = tsec->create_sid;
+       else if (!strcmp(name, "keycreate"))
+               sid = tsec->keycreate_sid;
+       else if (!strcmp(name, "sockcreate"))
+               sid = tsec->sockcreate_sid;
        else
                return -EINVAL;
 
        if (!sid)
                return 0;
 
-       error = security_sid_to_context(sid, &context, &len);
-       if (error)
-               return error;
-       if (len > size) {
-               kfree(context);
-               return -ERANGE;
-       }
-       memcpy(value, context, len);
-       kfree(context);
-       return len;
+       return selinux_getsecurity(sid, value, size);
 }
 
 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;
 
-       if (current != p || !strcmp(name, "current")) {
+       if (current != p) {
                /* SELinux only allows a process to change its own
-                  security attributes, and it only allows the process
-                  current SID to change via exec. */
+                  security attributes. */
                return -EACCES;
        }
 
@@ -4164,14 +4481,23 @@ static int selinux_setprocattr(struct task_struct *p,
                error = task_has_perm(current, p, PROCESS__SETEXEC);
        else if (!strcmp(name, "fscreate"))
                error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+       else if (!strcmp(name, "keycreate"))
+               error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+       else if (!strcmp(name, "sockcreate"))
+               error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+       else if (!strcmp(name, "current"))
+               error = task_has_perm(current, p, PROCESS__SETCURRENT);
        else
                error = -EINVAL;
        if (error)
                return error;
 
        /* Obtain a SID for the context, if one was specified. */
-       if (size) {
-               int error;
+       if (size && str[1] && str[1] != '\n') {
+               if (str[size-1] == '\n') {
+                       str[size-1] = 0;
+                       size--;
+               }
                error = security_context_to_sid(value, size, &sid);
                if (error)
                        return error;
@@ -4188,13 +4514,137 @@ static int selinux_setprocattr(struct task_struct *p,
                tsec->exec_sid = sid;
        else if (!strcmp(name, "fscreate"))
                tsec->create_sid = sid;
+       else if (!strcmp(name, "keycreate")) {
+               error = may_create_key(sid, p);
+               if (error)
+                       return error;
+               tsec->keycreate_sid = sid;
+       } else if (!strcmp(name, "sockcreate"))
+               tsec->sockcreate_sid = sid;
+       else if (!strcmp(name, "current")) {
+               struct av_decision avd;
+
+               if (sid == 0)
+                       return -EINVAL;
+
+               /* Only allow single threaded processes to change context */
+               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)
+                               if (t->mm == mm && t != p) {
+                                       read_unlock(&tasklist_lock);
+                                       return -EPERM;
+                               }
+                       while_each_thread(g, t);
+                       read_unlock(&tasklist_lock);
+                }
+
+               /* Check permissions for the transition. */
+               error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+                                    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);
+               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, &avd);
+                       if (!error)
+                               tsec->sid = sid;
+                       task_unlock(p);
+                       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
                return -EINVAL;
 
        return size;
 }
 
-struct security_operations selinux_ops = {
+static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+       return security_sid_to_context(secid, secdata, seclen);
+}
+
+static void selinux_release_secctx(char *secdata, u32 seclen)
+{
+       if (secdata)
+               kfree(secdata);
+}
+
+#ifdef CONFIG_KEYS
+
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+                            unsigned long flags)
+{
+       struct task_security_struct *tsec = tsk->security;
+       struct key_security_struct *ksec;
+
+       ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
+       if (!ksec)
+               return -ENOMEM;
+
+       ksec->obj = k;
+       if (tsec->keycreate_sid)
+               ksec->sid = tsec->keycreate_sid;
+       else
+               ksec->sid = tsec->sid;
+       k->security = ksec;
+
+       return 0;
+}
+
+static void selinux_key_free(struct key *k)
+{
+       struct key_security_struct *ksec = k->security;
+
+       k->security = NULL;
+       kfree(ksec);
+}
+
+static int selinux_key_permission(key_ref_t key_ref,
+                           struct task_struct *ctx,
+                           key_perm_t perm)
+{
+       struct key *key;
+       struct task_security_struct *tsec;
+       struct key_security_struct *ksec;
+
+       key = key_ref_to_ptr(key_ref);
+
+       tsec = ctx->security;
+       ksec = key->security;
+
+       /* if no specific permissions are requested, we skip the
+          permission check. No serious, additional covert channels
+          appear to be created. */
+       if (perm == 0)
+               return 0;
+
+       return avc_has_perm(tsec->sid, ksec->sid,
+                           SECCLASS_KEY, perm, NULL);
+}
+
+#endif
+
+static struct security_operations selinux_ops = {
        .ptrace =                       selinux_ptrace,
        .capget =                       selinux_capget,
        .capset_check =                 selinux_capset_check,
@@ -4212,6 +4662,7 @@ struct security_operations selinux_ops = {
        .bprm_alloc_security =          selinux_bprm_alloc_security,
        .bprm_free_security =           selinux_bprm_free_security,
        .bprm_apply_creds =             selinux_bprm_apply_creds,
+       .bprm_post_apply_creds =        selinux_bprm_post_apply_creds,
        .bprm_set_security =            selinux_bprm_set_security,
        .bprm_check_security =          selinux_bprm_check_security,
        .bprm_secureexec =              selinux_bprm_secureexec,
@@ -4226,20 +4677,15 @@ struct security_operations selinux_ops = {
 
        .inode_alloc_security =         selinux_inode_alloc_security,
        .inode_free_security =          selinux_inode_free_security,
+       .inode_init_security =          selinux_inode_init_security,
        .inode_create =                 selinux_inode_create,
-       .inode_post_create =            selinux_inode_post_create,
        .inode_link =                   selinux_inode_link,
-       .inode_post_link =              selinux_inode_post_link,
        .inode_unlink =                 selinux_inode_unlink,
        .inode_symlink =                selinux_inode_symlink,
-       .inode_post_symlink =           selinux_inode_post_symlink,
        .inode_mkdir =                  selinux_inode_mkdir,
-       .inode_post_mkdir =             selinux_inode_post_mkdir,
        .inode_rmdir =                  selinux_inode_rmdir,
        .inode_mknod =                  selinux_inode_mknod,
-       .inode_post_mknod =             selinux_inode_post_mknod,
        .inode_rename =                 selinux_inode_rename,
-       .inode_post_rename =            selinux_inode_post_rename,
        .inode_readlink =               selinux_inode_readlink,
        .inode_follow_link =            selinux_inode_follow_link,
        .inode_permission =             selinux_inode_permission,
@@ -4250,6 +4696,7 @@ struct security_operations selinux_ops = {
        .inode_getxattr =               selinux_inode_getxattr,
        .inode_listxattr =              selinux_inode_listxattr,
        .inode_removexattr =            selinux_inode_removexattr,
+       .inode_xattr_getsuffix =        selinux_inode_xattr_getsuffix,
        .inode_getsecurity =            selinux_inode_getsecurity,
        .inode_setsecurity =            selinux_inode_setsecurity,
        .inode_listsecurity =           selinux_inode_listsecurity,
@@ -4275,11 +4722,15 @@ struct security_operations selinux_ops = {
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
+       .task_getsecid =                selinux_task_getsecid,
        .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
+       .task_setioprio =               selinux_task_setioprio,
+       .task_getioprio =               selinux_task_getioprio,
        .task_setrlimit =               selinux_task_setrlimit,
        .task_setscheduler =            selinux_task_setscheduler,
        .task_getscheduler =            selinux_task_getscheduler,
+       .task_movememory =              selinux_task_movememory,
        .task_kill =                    selinux_task_kill,
        .task_wait =                    selinux_task_wait,
        .task_prctl =                   selinux_task_prctl,
@@ -4318,7 +4769,9 @@ struct security_operations selinux_ops = {
        .getprocattr =                  selinux_getprocattr,
        .setprocattr =                  selinux_setprocattr,
 
-#ifdef CONFIG_SECURITY_NETWORK
+       .secid_to_secctx =              selinux_secid_to_secctx,
+       .release_secctx =               selinux_release_secctx,
+
         .unix_stream_connect =         selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
 
@@ -4336,13 +4789,39 @@ struct security_operations selinux_ops = {
        .socket_setsockopt =            selinux_socket_setsockopt,
        .socket_shutdown =              selinux_socket_shutdown,
        .socket_sock_rcv_skb =          selinux_socket_sock_rcv_skb,
-       .socket_getpeersec =            selinux_socket_getpeersec,
+       .socket_getpeersec_stream =     selinux_socket_getpeersec_stream,
+       .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
        .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,
+       .sock_graft =                   selinux_sock_graft,
+       .inet_conn_request =            selinux_inet_conn_request,
+       .inet_csk_clone =               selinux_inet_csk_clone,
+       .inet_conn_established =        selinux_inet_conn_established,
+       .req_classify_flow =            selinux_req_classify_flow,
+
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+       .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
+       .xfrm_policy_clone_security =   selinux_xfrm_policy_clone,
+       .xfrm_policy_free_security =    selinux_xfrm_policy_free,
+       .xfrm_policy_delete_security =  selinux_xfrm_policy_delete,
+       .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_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,
 #endif
 };
 
-__init int selinux_init(void)
+static __init int selinux_init(void)
 {
        struct task_security_struct *tsec;
 
@@ -4359,6 +4838,9 @@ __init int selinux_init(void)
        tsec = current->security;
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
 
+       sel_inode_cache = kmem_cache_create("selinux_inode_security",
+                                           sizeof(struct inode_security_struct),
+                                           0, SLAB_PANIC, NULL, NULL);
        avc_init();
 
        original_ops = secondary_ops = security_ops;
@@ -4372,6 +4854,15 @@ __init int selinux_init(void)
        } else {
                printk(KERN_INFO "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;
 }
 
@@ -4381,6 +4872,7 @@ void selinux_complete_init(void)
 
        /* Set up any superblocks initialized prior to the policy load. */
        printk(KERN_INFO "SELinux:  Setting up existing superblocks.\n");
+       spin_lock(&sb_lock);
        spin_lock(&sb_security_lock);
 next_sb:
        if (!list_empty(&superblock_security_head)) {
@@ -4389,26 +4881,27 @@ next_sb:
                                           struct superblock_security_struct,
                                           list);
                struct super_block *sb = sbsec->sb;
-               spin_lock(&sb_lock);
                sb->s_count++;
-               spin_unlock(&sb_lock);
                spin_unlock(&sb_security_lock);
+               spin_unlock(&sb_lock);
                down_read(&sb->s_umount);
                if (sb->s_root)
                        superblock_doinit(sb, NULL);
                drop_super(sb);
+               spin_lock(&sb_lock);
                spin_lock(&sb_security_lock);
                list_del_init(&sbsec->list);
                goto next_sb;
        }
        spin_unlock(&sb_security_lock);
+       spin_unlock(&sb_lock);
 }
 
 /* SELinux requires early initialization in order to label
    all processes and objects when they are created. */
 security_initcall(selinux_init);
 
-#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_NETFILTER)
+#if defined(CONFIG_NETFILTER)
 
 static struct nf_hook_ops selinux_ipv4_op = {
        .hook =         selinux_ipv4_postroute_last,
@@ -4450,6 +4943,7 @@ static int __init selinux_nf_ip_init(void)
                panic("SELinux: nf_register_hook for IPv6: error %d\n", err);
 
 #endif /* IPV6 */
+
 out:
        return err;
 }
@@ -4468,13 +4962,13 @@ static void selinux_nf_ip_exit(void)
 }
 #endif
 
-#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
+#else /* CONFIG_NETFILTER */
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 #define selinux_nf_ip_exit()
 #endif
 
-#endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
+#endif /* CONFIG_NETFILTER */
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 int selinux_disable(void)
@@ -4495,6 +4989,7 @@ int selinux_disable(void)
        printk(KERN_INFO "SELinux:  Disabled at runtime.\n");
 
        selinux_disabled = 1;
+       selinux_enabled = 0;
 
        /* Reset security_ops to the secondary module, dummy or capability. */
        security_ops = secondary_ops;