Security: split proc ptrace checking into read vs. attach
[safe/jmp/linux-2.6] / security / selinux / hooks.c
index 75c2e99..4be1563 100644 (file)
@@ -4,22 +4,22 @@
  *  This file contains the SELinux hook function implementations.
  *
  *  Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
- *            Chris Vance, <cvance@nai.com>
- *            Wayne Salamon, <wsalamon@nai.com>
- *            James Morris <jmorris@redhat.com>
+ *           Chris Vance, <cvance@nai.com>
+ *           Wayne Salamon, <wsalamon@nai.com>
+ *           James Morris <jmorris@redhat.com>
  *
  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
  *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
- *                          <dgoeddel@trustedcs.com>
+ *                         <dgoeddel@trustedcs.com>
  *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
- *                Paul Moore <paul.moore@hp.com>
+ *             Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
- *                     Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2,
- *      as published by the Free Software Foundation.
+ *     as published by the Free Software Foundation.
  */
 
 #include <linux/init.h>
@@ -39,6 +39,7 @@
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/ext2_fs.h>
@@ -52,7 +53,7 @@
 #include <net/tcp.h>           /* struct or_callable used in sock_rcv_skb */
 #include <net/net_namespace.h>
 #include <net/netlabel.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
 #include <linux/bitops.h>
 #include "objsec.h"
 #include "netif.h"
 #include "netnode.h"
+#include "netport.h"
 #include "xfrm.h"
 #include "netlabel.h"
+#include "audit.h"
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -97,11 +100,13 @@ extern struct security_operations *security_ops;
 atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
-int selinux_enforcing = 0;
+int selinux_enforcing;
 
 static int __init enforcing_setup(char *str)
 {
-       selinux_enforcing = simple_strtol(str,NULL,0);
+       unsigned long enforcing;
+       if (!strict_strtoul(str, 0, &enforcing))
+               selinux_enforcing = enforcing ? 1 : 0;
        return 1;
 }
 __setup("enforcing=", enforcing_setup);
@@ -112,7 +117,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
 
 static int __init selinux_enabled_setup(char *str)
 {
-       selinux_enabled = simple_strtol(str, NULL, 0);
+       unsigned long enabled;
+       if (!strict_strtoul(str, 0, &enabled))
+               selinux_enabled = enabled ? 1 : 0;
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
@@ -121,13 +128,13 @@ int selinux_enabled = 1;
 #endif
 
 /* Original (dummy) security module. */
-static struct security_operations *original_ops = NULL;
+static struct security_operations *original_ops;
 
 /* Minimal support for a secondary security module,
    just to allow the use of the dummy or capability modules.
    The owlsm module can alternatively be used as a secondary
    module as long as CONFIG_OWLSM_FD is not enabled. */
-static struct security_operations *secondary_ops = NULL;
+static struct security_operations *secondary_ops;
 
 /* Lists of inode and superblock security structures initialized
    before the policy was loaded. */
@@ -161,8 +168,7 @@ static int task_alloc_security(struct task_struct *task)
        if (!tsec)
                return -ENOMEM;
 
-       tsec->task = task;
-       tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
+       tsec->osid = tsec->sid = SECINITSID_UNLABELED;
        task->security = tsec;
 
        return 0;
@@ -180,7 +186,7 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kmem_cache_zalloc(sel_inode_cache, GFP_KERNEL);
+       isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
        if (!isec)
                return -ENOMEM;
 
@@ -218,7 +224,6 @@ static int file_alloc_security(struct file *file)
        if (!fsec)
                return -ENOMEM;
 
-       fsec->file = file;
        fsec->sid = tsec->sid;
        fsec->fown_sid = tsec->sid;
        file->f_security = fsec;
@@ -275,12 +280,11 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
        if (!ssec)
                return -ENOMEM;
 
-       ssec->sk = sk;
        ssec->peer_sid = SECINITSID_UNLABELED;
        ssec->sid = SECINITSID_UNLABELED;
        sk->sk_security = ssec;
 
-       selinux_netlbl_sk_security_init(ssec, family);
+       selinux_netlbl_sk_security_reset(ssec, family);
 
        return 0;
 }
@@ -324,10 +328,10 @@ enum {
 };
 
 static match_table_t tokens = {
-       {Opt_context, "context=%s"},
-       {Opt_fscontext, "fscontext=%s"},
-       {Opt_defcontext, "defcontext=%s"},
-       {Opt_rootcontext, "rootcontext=%s"},
+       {Opt_context, CONTEXT_STR "%s"},
+       {Opt_fscontext, FSCONTEXT_STR "%s"},
+       {Opt_defcontext, DEFCONTEXT_STR "%s"},
+       {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
        {Opt_error, NULL},
 };
 
@@ -443,8 +447,7 @@ out:
  * mount options, or whatever.
  */
 static int selinux_get_mnt_opts(const struct super_block *sb,
-                               char ***mount_options, int **mnt_opts_flags,
-                               int *num_opts)
+                               struct security_mnt_opts *opts)
 {
        int rc = 0, i;
        struct superblock_security_struct *sbsec = sb->s_security;
@@ -452,9 +455,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
        u32 len;
        char tmp;
 
-       *num_opts = 0;
-       *mount_options = NULL;
-       *mnt_opts_flags = NULL;
+       security_init_mnt_opts(opts);
 
        if (!sbsec->initialized)
                return -EINVAL;
@@ -470,18 +471,18 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
        /* count the number of mount options for this sb */
        for (i = 0; i < 8; i++) {
                if (tmp & 0x01)
-                       (*num_opts)++;
+                       opts->num_mnt_opts++;
                tmp >>= 1;
        }
 
-       *mount_options = kcalloc(*num_opts, sizeof(char *), GFP_ATOMIC);
-       if (!*mount_options) {
+       opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
+       if (!opts->mnt_opts) {
                rc = -ENOMEM;
                goto out_free;
        }
 
-       *mnt_opts_flags = kcalloc(*num_opts, sizeof(int), GFP_ATOMIC);
-       if (!*mnt_opts_flags) {
+       opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
+       if (!opts->mnt_opts_flags) {
                rc = -ENOMEM;
                goto out_free;
        }
@@ -491,22 +492,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                rc = security_sid_to_context(sbsec->sid, &context, &len);
                if (rc)
                        goto out_free;
-               (*mount_options)[i] = context;
-               (*mnt_opts_flags)[i++] = FSCONTEXT_MNT;
+               opts->mnt_opts[i] = context;
+               opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
        }
        if (sbsec->flags & CONTEXT_MNT) {
                rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
                if (rc)
                        goto out_free;
-               (*mount_options)[i] = context;
-               (*mnt_opts_flags)[i++] = CONTEXT_MNT;
+               opts->mnt_opts[i] = context;
+               opts->mnt_opts_flags[i++] = CONTEXT_MNT;
        }
        if (sbsec->flags & DEFCONTEXT_MNT) {
                rc = security_sid_to_context(sbsec->def_sid, &context, &len);
                if (rc)
                        goto out_free;
-               (*mount_options)[i] = context;
-               (*mnt_opts_flags)[i++] = DEFCONTEXT_MNT;
+               opts->mnt_opts[i] = context;
+               opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
        }
        if (sbsec->flags & ROOTCONTEXT_MNT) {
                struct inode *root = sbsec->sb->s_root->d_inode;
@@ -515,24 +516,16 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
                rc = security_sid_to_context(isec->sid, &context, &len);
                if (rc)
                        goto out_free;
-               (*mount_options)[i] = context;
-               (*mnt_opts_flags)[i++] = ROOTCONTEXT_MNT;
+               opts->mnt_opts[i] = context;
+               opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
        }
 
-       BUG_ON(i != *num_opts);
+       BUG_ON(i != opts->num_mnt_opts);
 
        return 0;
 
 out_free:
-       /* don't leak context string if security_sid_to_context had an error */
-       if (*mount_options && i)
-               for (; i > 0; i--)
-                       kfree((*mount_options)[i-1]);
-       kfree(*mount_options);
-       *mount_options = NULL;
-       kfree(*mnt_opts_flags);
-       *mnt_opts_flags = NULL;
-       *num_opts = 0;
+       security_free_mnt_opts(opts);
        return rc;
 }
 
@@ -553,12 +546,13 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
                        return 1;
        return 0;
 }
+
 /*
  * Allow filesystems with binary mount data to explicitly set mount point
  * labeling information.
  */
-static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
-                               int *flags, int num_opts)
+static int selinux_set_mnt_opts(struct super_block *sb,
+                               struct security_mnt_opts *opts)
 {
        int rc = 0, i;
        struct task_security_struct *tsec = current->security;
@@ -568,6 +562,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
        struct inode_security_struct *root_isec = inode->i_security;
        u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
        u32 defcontext_sid = 0;
+       char **mount_options = opts->mnt_opts;
+       int *flags = opts->mnt_opts_flags;
+       int num_opts = opts->num_mnt_opts;
 
        mutex_lock(&sbsec->lock);
 
@@ -583,12 +580,27 @@ static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
                        goto out;
                }
                rc = -EINVAL;
-               printk(KERN_WARNING "Unable to set superblock options before "
-                      "the security server is initialized\n");
+               printk(KERN_WARNING "SELinux: Unable to set superblock options "
+                       "before the security server is initialized\n");
                goto out;
        }
 
        /*
+        * Binary mount data FS will come through this function twice.  Once
+        * from an explicit call and once from the generic calls from the vfs.
+        * Since the generic VFS calls will not contain any security mount data
+        * we need to skip the double mount verification.
+        *
+        * This does open a hole in which we will not notice if the first
+        * mount using this sb set explict options and a second mount using
+        * this sb does not set any security options.  (The first options
+        * will be used for both mounts)
+        */
+       if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+           && (num_opts == 0))
+               goto out;
+
+       /*
         * parse the mount options, check if they are valid sids.
         * also check if someone is trying to mount the same sb more
         * than once with different security options.
@@ -663,7 +675,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
        rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
-                      __FUNCTION__, sb->s_type->name, rc);
+                      __func__, sb->s_type->name, rc);
                goto out;
        }
 
@@ -748,17 +760,26 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        int set_context =       (oldsbsec->flags & CONTEXT_MNT);
        int set_rootcontext =   (oldsbsec->flags & ROOTCONTEXT_MNT);
 
-       /* we can't error, we can't save the info, this shouldn't get called
-        * this early in the boot process. */
-       BUG_ON(!ss_initialized);
-
-       /* this might go away sometime down the line if there is a new user
-        * of clone, but for now, nfs better not get here... */
-       BUG_ON(newsbsec->initialized);
+       /*
+        * if the parent was able to be mounted it clearly had no special lsm
+        * mount options.  thus we can safely put this sb on the list and deal
+        * with it later
+        */
+       if (!ss_initialized) {
+               spin_lock(&sb_security_lock);
+               if (list_empty(&newsbsec->list))
+                       list_add(&newsbsec->list, &superblock_security_head);
+               spin_unlock(&sb_security_lock);
+               return;
+       }
 
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!oldsbsec->initialized);
 
+       /* if fs is reusing a sb, just let its options stand... */
+       if (newsbsec->initialized)
+               return;
+
        mutex_lock(&newsbsec->lock);
 
        newsbsec->flags = oldsbsec->flags;
@@ -792,43 +813,15 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        mutex_unlock(&newsbsec->lock);
 }
 
-/*
- * string mount options parsing and call set the sbsec
- */
-static int superblock_doinit(struct super_block *sb, void *data)
+static int selinux_parse_opts_str(char *options,
+                                 struct security_mnt_opts *opts)
 {
+       char *p;
        char *context = NULL, *defcontext = NULL;
        char *fscontext = NULL, *rootcontext = NULL;
-       int rc = 0;
-       char *p, *options = data;
-       /* selinux only know about a fixed number of mount options */
-       char *mnt_opts[NUM_SEL_MNT_OPTS];
-       int mnt_opts_flags[NUM_SEL_MNT_OPTS], num_mnt_opts = 0;
-
-       if (!data)
-               goto out;
+       int rc, num_mnt_opts = 0;
 
-       /* with the nfs patch this will become a goto out; */
-       if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) {
-               const char *name = sb->s_type->name;
-               /* NFS we understand. */
-               if (!strcmp(name, "nfs")) {
-                       struct nfs_mount_data *d = data;
-
-                       if (d->version !=  NFS_MOUNT_VERSION)
-                               goto out;
-
-                       if (d->context[0]) {
-                               context = kstrdup(d->context, GFP_KERNEL);
-                               if (!context) {
-                                       rc = -ENOMEM;
-                                       goto out;
-                               }
-                       }
-                       goto build_flags;
-               } else
-                       goto out;
-       }
+       opts->num_mnt_opts = 0;
 
        /* Standard string-based options. */
        while ((p = strsep(&options, "|")) != NULL) {
@@ -901,26 +894,37 @@ static int superblock_doinit(struct super_block *sb, void *data)
                }
        }
 
-build_flags:
+       rc = -ENOMEM;
+       opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
+       if (!opts->mnt_opts)
+               goto out_err;
+
+       opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
+       if (!opts->mnt_opts_flags) {
+               kfree(opts->mnt_opts);
+               goto out_err;
+       }
+
        if (fscontext) {
-               mnt_opts[num_mnt_opts] = fscontext;
-               mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
+               opts->mnt_opts[num_mnt_opts] = fscontext;
+               opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
        }
        if (context) {
-               mnt_opts[num_mnt_opts] = context;
-               mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
+               opts->mnt_opts[num_mnt_opts] = context;
+               opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
        }
        if (rootcontext) {
-               mnt_opts[num_mnt_opts] = rootcontext;
-               mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
+               opts->mnt_opts[num_mnt_opts] = rootcontext;
+               opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
        }
        if (defcontext) {
-               mnt_opts[num_mnt_opts] = defcontext;
-               mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
+               opts->mnt_opts[num_mnt_opts] = defcontext;
+               opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
        }
 
-out:
-       rc = selinux_set_mnt_opts(sb, mnt_opts, mnt_opts_flags, num_mnt_opts);
+       opts->num_mnt_opts = num_mnt_opts;
+       return 0;
+
 out_err:
        kfree(context);
        kfree(defcontext);
@@ -928,6 +932,33 @@ out_err:
        kfree(rootcontext);
        return rc;
 }
+/*
+ * string mount options parsing and call set the sbsec
+ */
+static int superblock_doinit(struct super_block *sb, void *data)
+{
+       int rc = 0;
+       char *options = data;
+       struct security_mnt_opts opts;
+
+       security_init_mnt_opts(&opts);
+
+       if (!data)
+               goto out;
+
+       BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);
+
+       rc = selinux_parse_opts_str(options, &opts);
+       if (rc)
+               goto out_err;
+
+out:
+       rc = selinux_set_mnt_opts(sb, &opts);
+
+out_err:
+       security_free_mnt_opts(&opts);
+       return rc;
+}
 
 static inline u16 inode_mode_to_security_class(umode_t mode)
 {
@@ -1037,7 +1068,7 @@ static int selinux_proc_get_sid(struct proc_dir_entry *de,
        int buflen, rc;
        char *buffer, *path, *end;
 
-       buffer = (char*)__get_free_page(GFP_KERNEL);
+       buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
@@ -1118,14 +1149,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        dentry = d_find_alias(inode);
                }
                if (!dentry) {
-                       printk(KERN_WARNING "%s:  no dentry for dev=%s "
-                              "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
+                       printk(KERN_WARNING "SELinux: %s:  no dentry for dev=%s "
+                              "ino=%ld\n", __func__, inode->i_sb->s_id,
                               inode->i_ino);
                        goto out_unlock;
                }
 
                len = INITCONTEXTLEN;
-               context = kmalloc(len, GFP_KERNEL);
+               context = kmalloc(len, GFP_NOFS);
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
@@ -1143,7 +1174,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        }
                        kfree(context);
                        len = rc;
-                       context = kmalloc(len, GFP_KERNEL);
+                       context = kmalloc(len, GFP_NOFS);
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
@@ -1156,8 +1187,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                dput(dentry);
                if (rc < 0) {
                        if (rc != -ENODATA) {
-                               printk(KERN_WARNING "%s:  getxattr returned "
-                                      "%d for dev=%s ino=%ld\n", __FUNCTION__,
+                               printk(KERN_WARNING "SELinux: %s:  getxattr returned "
+                                      "%d for dev=%s ino=%ld\n", __func__,
                                       -rc, inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
                                goto out_unlock;
@@ -1167,11 +1198,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        rc = 0;
                } else {
                        rc = security_context_to_sid_default(context, rc, &sid,
-                                                            sbsec->def_sid);
+                                                            sbsec->def_sid,
+                                                            GFP_NOFS);
                        if (rc) {
-                               printk(KERN_WARNING "%s:  context_to_sid(%s) "
+                               printk(KERN_WARNING "SELinux: %s:  context_to_sid(%s) "
                                       "returned %d for dev=%s ino=%ld\n",
-                                      __FUNCTION__, context, -rc,
+                                      __func__, context, -rc,
                                       inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
                                /* Leave with the unlabeled SID */
@@ -1287,7 +1319,7 @@ static int task_has_capability(struct task_struct *tsk,
 
        tsec = tsk->security;
 
-       AVC_AUDIT_DATA_INIT(&ad,CAP);
+       AVC_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
@@ -1330,7 +1362,7 @@ static int inode_has_perm(struct task_struct *tsk,
        struct inode_security_struct *isec;
        struct avc_audit_data ad;
 
-       if (unlikely (IS_PRIVATE (inode)))
+       if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
        tsec = tsk->security;
@@ -1355,7 +1387,7 @@ static inline int dentry_has_perm(struct task_struct *tsk,
 {
        struct inode *inode = dentry->d_inode;
        struct avc_audit_data ad;
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
        return inode_has_perm(tsk, inode, av, &ad);
@@ -1452,9 +1484,9 @@ static int may_create_key(u32 ksid,
        return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
 }
 
-#define MAY_LINK   0
-#define MAY_UNLINK 1
-#define MAY_RMDIR  2
+#define MAY_LINK       0
+#define MAY_UNLINK     1
+#define MAY_RMDIR      2
 
 /* Check whether a task can link, unlink, or rmdir a file/directory. */
 static int may_link(struct inode *dir,
@@ -1492,7 +1524,8 @@ static int may_link(struct inode *dir,
                av = DIR__RMDIR;
                break;
        default:
-               printk(KERN_WARNING "may_link:  unrecognized kind %d\n", kind);
+               printk(KERN_WARNING "SELinux: %s:  unrecognized kind %d\n",
+                       __func__, kind);
                return 0;
        }
 
@@ -1599,6 +1632,35 @@ static inline u32 file_mask_to_av(int mode, int mask)
        return av;
 }
 
+/*
+ * Convert a file mask to an access vector and include the correct open
+ * open permission.
+ */
+static inline u32 open_file_mask_to_av(int mode, int mask)
+{
+       u32 av = file_mask_to_av(mode, mask);
+
+       if (selinux_policycap_openperm) {
+               /*
+                * lnk files and socks do not really have an 'open'
+                */
+               if (S_ISREG(mode))
+                       av |= FILE__OPEN;
+               else if (S_ISCHR(mode))
+                       av |= CHR_FILE__OPEN;
+               else if (S_ISBLK(mode))
+                       av |= BLK_FILE__OPEN;
+               else if (S_ISFIFO(mode))
+                       av |= FIFO_FILE__OPEN;
+               else if (S_ISDIR(mode))
+                       av |= DIR__OPEN;
+               else
+                       printk(KERN_ERR "SELinux: WARNING: inside %s with "
+                               "unknown mode:%x\n", __func__, mode);
+       }
+       return av;
+}
+
 /* Convert a Linux file to an access vector. */
 static inline u32 file_to_av(struct file *file)
 {
@@ -1612,31 +1674,40 @@ static inline u32 file_to_av(struct file *file)
                else
                        av |= FILE__WRITE;
        }
+       if (!av) {
+               /*
+                * Special file opened with flags 3 for ioctl-only use.
+                */
+               av = FILE__IOCTL;
+       }
 
        return av;
 }
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
+static int selinux_ptrace(struct task_struct *parent,
+                         struct task_struct *child,
+                         unsigned int mode)
 {
-       struct task_security_struct *psec = parent->security;
-       struct task_security_struct *csec = child->security;
        int rc;
 
-       rc = secondary_ops->ptrace(parent,child);
+       rc = secondary_ops->ptrace(parent, child, mode);
        if (rc)
                return rc;
 
-       rc = task_has_perm(parent, child, PROCESS__PTRACE);
-       /* Save the SID of the tracing process for later use in apply_creds. */
-       if (!(child->ptrace & PT_PTRACED) && !rc)
-               csec->ptrace_sid = psec->sid;
-       return rc;
+       if (mode == PTRACE_MODE_READ) {
+               struct task_security_struct *tsec = parent->security;
+               struct task_security_struct *csec = child->security;
+               return avc_has_perm(tsec->sid, csec->sid,
+                                   SECCLASS_FILE, FILE__READ, NULL);
+       }
+
+       return task_has_perm(parent, child, PROCESS__PTRACE);
 }
 
 static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
-                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                         kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        int error;
 
@@ -1648,7 +1719,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
 }
 
 static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
-                                kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        int error;
 
@@ -1660,7 +1731,7 @@ static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effect
 }
 
 static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
-                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
+                              kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        secondary_ops->capset_set(target, effective, inheritable, permitted);
 }
@@ -1673,7 +1744,7 @@ static int selinux_capable(struct task_struct *tsk, int cap)
        if (rc)
                return rc;
 
-       return task_has_capability(tsk,cap);
+       return task_has_capability(tsk, cap);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -1682,7 +1753,7 @@ static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
        char *buffer, *path, *end;
 
        rc = -ENOMEM;
-       buffer = (char*)__get_free_page(GFP_KERNEL);
+       buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                goto out;
 
@@ -1740,7 +1811,7 @@ static int selinux_sysctl(ctl_table *table, int op)
 
        /* The op values are "defined" in sysctl.c, thereby creating
         * a bad coupling between this module and sysctl.c */
-       if(op == 001) {
+       if (op == 001) {
                error = avc_has_perm(tsec->sid, tsid,
                                     SECCLASS_DIR, DIR__SEARCH, NULL);
        } else {
@@ -1752,7 +1823,7 @@ static int selinux_sysctl(ctl_table *table, int op)
                if (av)
                        error = avc_has_perm(tsec->sid, tsid,
                                             SECCLASS_FILE, av, NULL);
-        }
+       }
 
        return error;
 }
@@ -1765,25 +1836,23 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
                return 0;
 
        switch (cmds) {
-               case Q_SYNC:
-               case Q_QUOTAON:
-               case Q_QUOTAOFF:
-               case Q_SETINFO:
-               case Q_SETQUOTA:
-                       rc = superblock_has_perm(current,
-                                                sb,
-                                                FILESYSTEM__QUOTAMOD, NULL);
-                       break;
-               case Q_GETFMT:
-               case Q_GETINFO:
-               case Q_GETQUOTA:
-                       rc = superblock_has_perm(current,
-                                                sb,
-                                                FILESYSTEM__QUOTAGET, NULL);
-                       break;
-               default:
-                       rc = 0;  /* let the kernel handle invalid cmds */
-                       break;
+       case Q_SYNC:
+       case Q_QUOTAON:
+       case Q_QUOTAOFF:
+       case Q_SETINFO:
+       case Q_SETQUOTA:
+               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
+                                        NULL);
+               break;
+       case Q_GETFMT:
+       case Q_GETINFO:
+       case Q_GETQUOTA:
+               rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
+                                        NULL);
+               break;
+       default:
+               rc = 0;  /* let the kernel handle invalid cmds */
+               break;
        }
        return rc;
 }
@@ -1802,23 +1871,23 @@ static int selinux_syslog(int type)
                return rc;
 
        switch (type) {
-               case 3:         /* Read last kernel messages */
-               case 10:        /* Return size of the log buffer */
-                       rc = task_has_system(current, SYSTEM__SYSLOG_READ);
-                       break;
-               case 6:         /* Disable logging to console */
-               case 7:         /* Enable logging to console */
-               case 8:         /* Set level of messages printed to console */
-                       rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
-                       break;
-               case 0:         /* Close log */
-               case 1:         /* Open log */
-               case 2:         /* Read from log */
-               case 4:         /* Read/clear last kernel messages */
-               case 5:         /* Clear ring buffer */
-               default:
-                       rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
-                       break;
+       case 3:         /* Read last kernel messages */
+       case 10:        /* Return size of the log buffer */
+               rc = task_has_system(current, SYSTEM__SYSLOG_READ);
+               break;
+       case 6:         /* Disable logging to console */
+       case 7:         /* Enable logging to console */
+       case 8:         /* Set level of messages printed to console */
+               rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
+               break;
+       case 0:         /* Close log */
+       case 1:         /* Open log */
+       case 2:         /* Read from log */
+       case 4:         /* Read/clear last kernel messages */
+       case 5:         /* Clear ring buffer */
+       default:
+               rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
+               break;
        }
        return rc;
 }
@@ -1854,6 +1923,22 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
        return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
 
+/**
+ * task_tracer_task - return the task that is tracing the given task
+ * @task:              task to consider
+ *
+ * Returns NULL if noone is tracing @task, or the &struct task_struct
+ * pointer to its tracer.
+ *
+ * Must be called under rcu_read_lock().
+ */
+static struct task_struct *task_tracer_task(struct task_struct *task)
+{
+       if (task->ptrace & PT_PTRACED)
+               return rcu_dereference(task->parent);
+       return NULL;
+}
+
 /* binprm security operations */
 
 static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
@@ -1864,7 +1949,6 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
        if (!bsec)
                return -ENOMEM;
 
-       bsec->bprm = bprm;
        bsec->sid = SECINITSID_UNLABELED;
        bsec->set = 0;
 
@@ -1909,7 +1993,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &newsid);
+                                            SECCLASS_PROCESS, &newsid);
                if (rc)
                        return rc;
        }
@@ -1920,7 +2004,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                newsid = tsec->sid;
 
-        if (tsec->sid == newsid) {
+       if (tsec->sid == newsid) {
                rc = avc_has_perm(tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
                if (rc)
@@ -1948,13 +2032,13 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
        return 0;
 }
 
-static int selinux_bprm_check_security (struct linux_binprm *bprm)
+static int selinux_bprm_check_security(struct linux_binprm *bprm)
 {
        return secondary_ops->bprm_check_security(bprm);
 }
 
 
-static int selinux_bprm_secureexec (struct linux_binprm *bprm)
+static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
        struct task_security_struct *tsec = current->security;
        int atsecure = 0;
@@ -1981,7 +2065,7 @@ extern struct vfsmount *selinuxfs_mount;
 extern struct dentry *selinux_null;
 
 /* Derived from fs/exec.c:flush_old_files. */
-static inline void flush_unauthorized_files(struct files_struct * files)
+static inline void flush_unauthorized_files(struct files_struct *files)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
@@ -2016,7 +2100,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
 
        /* Revalidate access to inherited open files. */
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2032,7 +2116,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                if (!set)
                        continue;
                spin_unlock(&files->file_lock);
-               for ( ; set ; i++,set >>= 1) {
+               for ( ; set ; i++, set >>= 1) {
                        if (set & 1) {
                                file = fget(i);
                                if (!file)
@@ -2101,12 +2185,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and kill. */
                if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-                       rc = avc_has_perm(tsec->ptrace_sid, sid,
-                                         SECCLASS_PROCESS, PROCESS__PTRACE,
-                                         NULL);
-                       if (rc) {
-                               bsec->unsafe = 1;
-                               return;
+                       struct task_struct *tracer;
+                       struct task_security_struct *sec;
+                       u32 ptsid = 0;
+
+                       rcu_read_lock();
+                       tracer = task_tracer_task(current);
+                       if (likely(tracer != NULL)) {
+                               sec = tracer->security;
+                               ptsid = sec->sid;
+                       }
+                       rcu_read_unlock();
+
+                       if (ptsid != 0) {
+                               rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+                                                 PROCESS__PTRACE, NULL);
+                               if (rc) {
+                                       bsec->unsafe = 1;
+                                       return;
+                               }
                        }
                }
                tsec->sid = sid;
@@ -2176,7 +2273,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
                for (i = 0; i < RLIM_NLIMITS; i++) {
                        rlim = current->signal->rlim + i;
                        initrlim = init_task.signal->rlim+i;
-                       rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur);
+                       rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
                }
                if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
                        /*
@@ -2214,10 +2311,10 @@ static inline int match_prefix(char *prefix, int plen, char *option, int olen)
 
 static inline int selinux_option(char *option, int len)
 {
-       return (match_prefix("context=", sizeof("context=")-1, option, len) ||
-               match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) ||
-               match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) ||
-               match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len));
+       return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
+               match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
+               match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
+               match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
@@ -2231,16 +2328,15 @@ static inline void take_option(char **to, char *from, int *first, int len)
        *to += len;
 }
 
-static inline void take_selinux_option(char **to, char *from, int *first, 
-                                      int len)
+static inline void take_selinux_option(char **to, char *from, int *first,
+                                      int len)
 {
        int current_size = 0;
 
        if (!*first) {
                **to = '|';
                *to += 1;
-       }
-       else
+       } else
                *first = 0;
 
        while (current_size < len) {
@@ -2253,7 +2349,7 @@ static inline void take_selinux_option(char **to, char *from, int *first,
        }
 }
 
-static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
+static int selinux_sb_copy_data(char *orig, char *copy)
 {
        int fnosec, fsec, rc = 0;
        char *in_save, *in_curr, *in_end;
@@ -2263,12 +2359,6 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
        in_curr = orig;
        sec_curr = copy;
 
-       /* Binary mount data: just copy */
-       if (type->fs_flags & FS_BINARY_MOUNTDATA) {
-               copy_page(sec_curr, in_curr);
-               goto out;
-       }
-
        nosec = (char *)get_zeroed_page(GFP_KERNEL);
        if (!nosec) {
                rc = -ENOMEM;
@@ -2310,7 +2400,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
        if (rc)
                return rc;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
        return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2319,29 +2409,29 @@ static int selinux_sb_statfs(struct dentry *dentry)
 {
        struct avc_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
-static int selinux_mount(char * dev_name,
-                         struct nameidata *nd,
-                         char * type,
-                         unsigned long flags,
-                         void * data)
+static int selinux_mount(char *dev_name,
+                        struct path *path,
+                        char *type,
+                        unsigned long flags,
+                        void *data)
 {
        int rc;
 
-       rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);
+       rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
        if (rc)
                return rc;
 
        if (flags & MS_REMOUNT)
-               return superblock_has_perm(current, nd->path.mnt->mnt_sb,
-                                          FILESYSTEM__REMOUNT, NULL);
+               return superblock_has_perm(current, path->mnt->mnt_sb,
+                                          FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(current, nd->path.mnt, nd->path.dentry,
-                                      FILE__MOUNTON);
+               return dentry_has_perm(current, path->mnt, path->dentry,
+                                      FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2352,8 +2442,8 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
        if (rc)
                return rc;
 
-       return superblock_has_perm(current,mnt->mnt_sb,
-                                  FILESYSTEM__UNMOUNT,NULL);
+       return superblock_has_perm(current, mnt->mnt_sb,
+                                  FILESYSTEM__UNMOUNT, NULL);
 }
 
 /* inode security operations */
@@ -2393,7 +2483,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                        printk(KERN_WARNING "%s:  "
                               "security_transition_sid failed, rc=%d (dev=%s "
                               "ino=%ld)\n",
-                              __FUNCTION__,
+                              __func__,
                               -rc, inode->i_sb->s_id, inode->i_ino);
                        return rc;
                }
@@ -2411,14 +2501,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                return -EOPNOTSUPP;
 
        if (name) {
-               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
+               namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS);
                if (!namep)
                        return -ENOMEM;
                *name = namep;
        }
 
        if (value && len) {
-               rc = security_sid_to_context(newsid, &context, &clen);
+               rc = security_sid_to_context_force(newsid, &context, &clen);
                if (rc) {
                        kfree(namep);
                        return rc;
@@ -2439,7 +2529,7 @@ static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, stru
 {
        int rc;
 
-       rc = secondary_ops->inode_link(old_dentry,dir,new_dentry);
+       rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
        if (rc)
                return rc;
        return may_link(dir, old_dentry, MAY_LINK);
@@ -2482,7 +2572,7 @@ static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mod
 }
 
 static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
-                                struct inode *new_inode, struct dentry *new_dentry)
+                               struct inode *new_inode, struct dentry *new_dentry)
 {
        return may_rename(old_inode, old_dentry, new_inode, new_dentry);
 }
@@ -2496,7 +2586,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 {
        int rc;
 
-       rc = secondary_ops->inode_follow_link(dentry,nameidata);
+       rc = secondary_ops->inode_follow_link(dentry, nameidata);
        if (rc)
                return rc;
        return dentry_has_perm(current, NULL, dentry, FILE__READ);
@@ -2517,7 +2607,7 @@ static int selinux_inode_permission(struct inode *inode, int mask,
        }
 
        return inode_has_perm(current, inode,
-                              file_mask_to_av(inode->i_mode, mask), NULL);
+                              open_file_mask_to_av(inode->i_mode, mask), NULL);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2543,7 +2633,7 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
        return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_setotherxattr(struct dentry *dentry, char *name)
+static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 {
        if (!strncmp(name, XATTR_SECURITY_PREFIX,
                     sizeof XATTR_SECURITY_PREFIX - 1)) {
@@ -2562,7 +2652,8 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, char *name)
        return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
 }
 
-static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
+static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
+                                 const void *value, size_t size, int flags)
 {
        struct task_security_struct *tsec = current->security;
        struct inode *inode = dentry->d_inode;
@@ -2582,7 +2673,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
        if (!is_owner_or_cap(inode))
                return -EPERM;
 
-       AVC_AUDIT_DATA_INIT(&ad,FS);
+       AVC_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
@@ -2591,6 +2682,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                return rc;
 
        rc = security_context_to_sid(value, size, &newsid);
+       if (rc == -EINVAL) {
+               if (!capable(CAP_MAC_ADMIN))
+                       return rc;
+               rc = security_context_to_sid_force(value, size, &newsid);
+       }
        if (rc)
                return rc;
 
@@ -2600,7 +2696,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                return rc;
 
        rc = security_validate_transition(isec->sid, newsid, tsec->sid,
-                                         isec->sclass);
+                                         isec->sclass);
        if (rc)
                return rc;
 
@@ -2611,8 +2707,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
                            &ad);
 }
 
-static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
-                                        void *value, size_t size, int flags)
+static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
+                                       const void *value, size_t size,
+                                       int flags)
 {
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
@@ -2624,10 +2721,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
                return;
        }
 
-       rc = security_context_to_sid(value, size, &newsid);
+       rc = security_context_to_sid_force(value, size, &newsid);
        if (rc) {
-               printk(KERN_WARNING "%s:  unable to obtain SID for context "
-                      "%s, rc=%d\n", __FUNCTION__, (char*)value, -rc);
+               printk(KERN_ERR "SELinux:  unable to map context to SID"
+                      "for (%s, %lu), rc=%d\n",
+                      inode->i_sb->s_id, inode->i_ino, -rc);
                return;
        }
 
@@ -2635,17 +2733,17 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
        return;
 }
 
-static int selinux_inode_getxattr (struct dentry *dentry, char *name)
+static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_listxattr (struct dentry *dentry)
+static int selinux_inode_listxattr(struct dentry *dentry)
 {
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
-static int selinux_inode_removexattr (struct dentry *dentry, char *name)
+static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
 {
        if (strcmp(name, XATTR_NAME_SELINUX))
                return selinux_inode_setotherxattr(dentry, name);
@@ -2686,7 +2784,7 @@ out_nofree:
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
-                                     const void *value, size_t size, int flags)
+                                    const void *value, size_t size, int flags)
 {
        struct inode_security_struct *isec = inode->i_security;
        u32 newsid;
@@ -2698,7 +2796,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid((void*)value, size, &newsid);
+       rc = security_context_to_sid((void *)value, size, &newsid);
        if (rc)
                return rc;
 
@@ -2724,6 +2822,12 @@ static int selinux_inode_killpriv(struct dentry *dentry)
        return secondary_ops->inode_killpriv(dentry);
 }
 
+static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+       struct inode_security_struct *isec = inode->i_security;
+       *secid = isec->sid;
+}
+
 /* file security operations */
 
 static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -2783,42 +2887,41 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        int error = 0;
 
        switch (cmd) {
-               case FIONREAD:
-               /* fall through */
-               case FIBMAP:
-               /* fall through */
-               case FIGETBSZ:
-               /* fall through */
-               case EXT2_IOC_GETFLAGS:
-               /* fall through */
-               case EXT2_IOC_GETVERSION:
-                       error = file_has_perm(current, file, FILE__GETATTR);
-                       break;
-
-               case EXT2_IOC_SETFLAGS:
-               /* fall through */
-               case EXT2_IOC_SETVERSION:
-                       error = file_has_perm(current, file, FILE__SETATTR);
-                       break;
+       case FIONREAD:
+       /* fall through */
+       case FIBMAP:
+       /* fall through */
+       case FIGETBSZ:
+       /* fall through */
+       case EXT2_IOC_GETFLAGS:
+       /* fall through */
+       case EXT2_IOC_GETVERSION:
+               error = file_has_perm(current, file, FILE__GETATTR);
+               break;
 
-               /* sys_ioctl() checks */
-               case FIONBIO:
-               /* fall through */
-               case FIOASYNC:
-                       error = file_has_perm(current, file, 0);
-                       break;
+       case EXT2_IOC_SETFLAGS:
+       /* fall through */
+       case EXT2_IOC_SETVERSION:
+               error = file_has_perm(current, file, FILE__SETATTR);
+               break;
 
-               case KDSKBENT:
-               case KDSKBSENT:
-                       error = task_has_capability(current,CAP_SYS_TTY_CONFIG);
-                       break;
+       /* sys_ioctl() checks */
+       case FIONBIO:
+       /* fall through */
+       case FIOASYNC:
+               error = file_has_perm(current, file, 0);
+               break;
 
-               /* default case assumes that the command will go
-                * to the file's ioctl() function.
-                */
-               default:
-                       error = file_has_perm(current, file, FILE__IOCTL);
+       case KDSKBENT:
+       case KDSKBSENT:
+               error = task_has_capability(current, CAP_SYS_TTY_CONFIG);
+               break;
 
+       /* default case assumes that the command will go
+        * to the file's ioctl() function.
+        */
+       default:
+               error = file_has_perm(current, file, FILE__IOCTL);
        }
        return error;
 }
@@ -2859,7 +2962,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
                             unsigned long addr, unsigned long addr_only)
 {
        int rc = 0;
-       u32 sid = ((struct task_security_struct*)(current->security))->sid;
+       u32 sid = ((struct task_security_struct *)(current->security))->sid;
 
        if (addr < mmap_min_addr)
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -2928,39 +3031,39 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
        int err = 0;
 
        switch (cmd) {
-               case F_SETFL:
-                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
-                               err = -EINVAL;
-                               break;
-                       }
+       case F_SETFL:
+               if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
+                       err = -EINVAL;
+                       break;
+               }
 
-                       if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
-                               err = file_has_perm(current, file,FILE__WRITE);
-                               break;
-                       }
-                       /* fall through */
-               case F_SETOWN:
-               case F_SETSIG:
-               case F_GETFL:
-               case F_GETOWN:
-               case F_GETSIG:
-                       /* Just check FD__USE permission */
-                       err = file_has_perm(current, file, 0);
+               if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
+                       err = file_has_perm(current, file, FILE__WRITE);
                        break;
-               case F_GETLK:
-               case F_SETLK:
-               case F_SETLKW:
+               }
+               /* fall through */
+       case F_SETOWN:
+       case F_SETSIG:
+       case F_GETFL:
+       case F_GETOWN:
+       case F_GETSIG:
+               /* Just check FD__USE permission */
+               err = file_has_perm(current, file, 0);
+               break;
+       case F_GETLK:
+       case F_SETLK:
+       case F_SETLKW:
 #if BITS_PER_LONG == 32
-               case F_GETLK64:
-               case F_SETLK64:
-               case F_SETLKW64:
+       case F_GETLK64:
+       case F_SETLK64:
+       case F_SETLKW64:
 #endif
-                       if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
-                               err = -EINVAL;
-                               break;
-                       }
-                       err = file_has_perm(current, file, FILE__LOCK);
+               if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
+                       err = -EINVAL;
                        break;
+               }
+               err = file_has_perm(current, file, FILE__LOCK);
+               break;
        }
 
        return err;
@@ -2981,13 +3084,13 @@ static int selinux_file_set_fowner(struct file *file)
 static int selinux_file_send_sigiotask(struct task_struct *tsk,
                                       struct fown_struct *fown, int signum)
 {
-        struct file *file;
+       struct file *file;
        u32 perm;
        struct task_security_struct *tsec;
        struct file_security_struct *fsec;
 
        /* struct fown_struct is never outside the context of a struct file */
-        file = container_of(fown, struct file, f_owner);
+       file = container_of(fown, struct file, f_owner);
 
        tsec = tsk->security;
        fsec = file->f_security;
@@ -3068,11 +3171,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
        tsec2->keycreate_sid = tsec1->keycreate_sid;
        tsec2->sockcreate_sid = tsec1->sockcreate_sid;
 
-       /* Retain ptracer SID across fork, if any.
-          This will be reset by the ptrace hook upon any
-          subsequent ptrace_attach operations. */
-       tsec2->ptrace_sid = tsec1->ptrace_sid;
-
        return 0;
 }
 
@@ -3094,7 +3192,7 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 
 static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 {
-       return secondary_ops->task_post_setuid(id0,id1,id2,flags);
+       return secondary_ops->task_post_setuid(id0, id1, id2, flags);
 }
 
 static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -3120,7 +3218,8 @@ static int selinux_task_getsid(struct task_struct *p)
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       selinux_get_task_sid(p, secid);
+       struct task_security_struct *tsec = p->security;
+       *secid = tsec->sid;
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -3137,7 +3236,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
        if (rc)
                return rc;
 
-       return task_has_perm(current,p, PROCESS__SETSCHED);
+       return task_has_perm(current, p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3207,9 +3306,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
        if (rc)
                return rc;
 
-       if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
-               return 0;
-
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
@@ -3226,12 +3322,13 @@ static int selinux_task_prctl(int option,
                              unsigned long arg2,
                              unsigned long arg3,
                              unsigned long arg4,
-                             unsigned long arg5)
+                             unsigned long arg5,
+                             long *rc_p)
 {
        /* The current prctl operations do not appear to require
           any SELinux controls since they merely observe or modify
           the state of the current process. */
-       return 0;
+       return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
 }
 
 static int selinux_task_wait(struct task_struct *p)
@@ -3241,7 +3338,7 @@ static int selinux_task_wait(struct task_struct *p)
 
 static void selinux_task_reparent_to_init(struct task_struct *p)
 {
-       struct task_security_struct *tsec;
+       struct task_security_struct *tsec;
 
        secondary_ops->task_reparent_to_init(p);
 
@@ -3286,11 +3383,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                *proto = ih->protocol;
 
        switch (ih->protocol) {
-        case IPPROTO_TCP: {
-               struct tcphdr _tcph, *th;
+       case IPPROTO_TCP: {
+               struct tcphdr _tcph, *th;
 
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
 
                offset += ihlen;
                th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
@@ -3300,23 +3397,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                ad->u.net.sport = th->source;
                ad->u.net.dport = th->dest;
                break;
-        }
-        
-        case IPPROTO_UDP: {
-               struct udphdr _udph, *uh;
-               
-               if (ntohs(ih->frag_off) & IP_OFFSET)
-                       break;
-                       
+       }
+
+       case IPPROTO_UDP: {
+               struct udphdr _udph, *uh;
+
+               if (ntohs(ih->frag_off) & IP_OFFSET)
+                       break;
+
                offset += ihlen;
-               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
                if (uh == NULL)
-                       break;  
+                       break;
 
-               ad->u.net.sport = uh->source;
-               ad->u.net.dport = uh->dest;
-               break;
-        }
+               ad->u.net.sport = uh->source;
+               ad->u.net.dport = uh->dest;
+               break;
+       }
 
        case IPPROTO_DCCP: {
                struct dccp_hdr _dccph, *dh;
@@ -3332,11 +3429,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
                ad->u.net.sport = dh->dccph_sport;
                ad->u.net.dport = dh->dccph_dport;
                break;
-        }
+       }
 
-        default:
-               break;
-        }
+       default:
+               break;
+       }
 out:
        return ret;
 }
@@ -3371,7 +3468,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
 
        switch (nexthdr) {
        case IPPROTO_TCP: {
-               struct tcphdr _tcph, *th;
+               struct tcphdr _tcph, *th;
 
                th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
                if (th == NULL)
@@ -3404,7 +3501,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
                ad->u.net.sport = dh->dccph_sport;
                ad->u.net.dport = dh->dccph_dport;
                break;
-        }
+       }
 
        /* includes fragments */
        default:
@@ -3502,7 +3599,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
        if (isec->sid == SECINITSID_KERNEL)
                goto out;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = sock->sk;
        err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
 
@@ -3608,13 +3705,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        inet_get_local_port_range(&low, &high);
 
                        if (snum < max(PROT_SOCK, low) || snum > high) {
-                               err = security_port_sid(sk->sk_family,
-                                                       sk->sk_type,
-                                                       sk->sk_protocol, snum,
-                                                       &sid);
+                               err = sel_netport_sid(sk->sk_protocol,
+                                                     snum, &sid);
                                if (err)
                                        goto out;
-                               AVC_AUDIT_DATA_INIT(&ad,NET);
+                               AVC_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
                                err = avc_has_perm(isec->sid, sid,
@@ -3624,12 +3719,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                        goto out;
                        }
                }
-               
-               switch(isec->sclass) {
+
+               switch (isec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
-                       
+
                case SECCLASS_UDP_SOCKET:
                        node_perm = UDP_SOCKET__NODE_BIND;
                        break;
@@ -3642,12 +3737,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        node_perm = RAWIP_SOCKET__NODE_BIND;
                        break;
                }
-               
+
                err = sel_netnode_sid(addrp, family, &sid);
                if (err)
                        goto out;
-               
-               AVC_AUDIT_DATA_INIT(&ad,NET);
+
+               AVC_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.sport = htons(snum);
                ad.u.net.family = family;
 
@@ -3657,7 +3752,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
                err = avc_has_perm(isec->sid, sid,
-                                  isec->sclass, node_perm, &ad);
+                                  isec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3699,15 +3794,14 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                        snum = ntohs(addr6->sin6_port);
                }
 
-               err = security_port_sid(sk->sk_family, sk->sk_type,
-                                       sk->sk_protocol, snum, &sid);
+               err = sel_netport_sid(sk->sk_protocol, snum, &sid);
                if (err)
                        goto out;
 
                perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               AVC_AUDIT_DATA_INIT(&ad,NET);
+               AVC_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
                err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
@@ -3745,7 +3839,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 }
 
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
-                                 int size)
+                                 int size)
 {
        int rc;
 
@@ -3772,7 +3866,7 @@ static int selinux_socket_getpeername(struct socket *sock)
        return socket_has_perm(current, sock, SOCKET__GETATTR);
 }
 
-static int selinux_socket_setsockopt(struct socket *sock,int level,int optname)
+static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
@@ -3811,7 +3905,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3823,7 +3917,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        /* connecting socket */
        ssec = sock->sk->sk_security;
        ssec->peer_sid = other_isec->sid;
-       
+
        /* server child socket */
        ssec = newsk->sk_security;
        ssec->peer_sid = isec->sid;
@@ -3843,7 +3937,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad,NET);
+       AVC_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3921,7 +4015,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
        err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
        if (err)
                return err;
-       
+
        err = sel_netnode_sid(addrp, family, &node_sid);
        if (err)
                return err;
@@ -3931,9 +4025,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
 
        if (!recv_perm)
                return 0;
-       err = security_port_sid(sk->sk_family, sk->sk_type,
-                               sk->sk_protocol, ntohs(ad->u.net.sport),
-                               &port_sid);
+       err = sel_netport_sid(sk->sk_protocol,
+                             ntohs(ad->u.net.sport), &port_sid);
        if (unlikely(err)) {
                printk(KERN_WARNING
                       "SELinux: failure in"
@@ -4073,7 +4166,7 @@ out_len:
                err = -EFAULT;
 
        kfree(scontext);
-out:   
+out:
        return err;
 }
 
@@ -4090,7 +4183,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
                goto out;
 
        if (sock && family == PF_UNIX)
-               selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
+               selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
        else if (skb)
                selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -4120,7 +4213,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
        newssec->peer_sid = ssec->peer_sid;
        newssec->sclass = ssec->sclass;
 
-       selinux_netlbl_sk_security_clone(ssec, newssec);
+       selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
 }
 
 static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4134,7 +4227,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
        }
 }
 
-static void selinux_sock_graft(struct socksk, struct socket *parent)
+static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
        struct sk_security_struct *sksec = sk->sk_security;
@@ -4211,13 +4304,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        struct nlmsghdr *nlh;
        struct socket *sock = sk->sk_socket;
        struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
-       
+
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
                goto out;
        }
        nlh = nlmsg_hdr(skb);
-       
+
        err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
@@ -4343,7 +4436,7 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
                return err;
        err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
                return err;
-               
+
        err = sel_netnode_sid(addrp, family, &node_sid);
        if (err)
                return err;
@@ -4354,9 +4447,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
        if (send_perm != 0)
                return 0;
 
-       err = security_port_sid(sk->sk_family, sk->sk_type,
-                               sk->sk_protocol, ntohs(ad->u.net.dport),
-                               &port_sid);
+       err = sel_netport_sid(sk->sk_protocol,
+                             ntohs(ad->u.net.dport), &port_sid);
        if (unlikely(err)) {
                printk(KERN_WARNING
                       "SELinux: failure in"
@@ -4527,7 +4619,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability)
        ad.u.cap = capability;
 
        return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
-                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
+                           SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
 }
 
 static int ipc_alloc_security(struct task_struct *task,
@@ -4542,7 +4634,6 @@ static int ipc_alloc_security(struct task_struct *task,
                return -ENOMEM;
 
        isec->sclass = sclass;
-       isec->ipc_perm = perm;
        isec->sid = tsec->sid;
        perm->security = isec;
 
@@ -4564,7 +4655,6 @@ static int msg_msg_alloc_security(struct msg_msg *msg)
        if (!msec)
                return -ENOMEM;
 
-       msec->msg = msg;
        msec->sid = SECINITSID_UNLABELED;
        msg->security = msec;
 
@@ -4621,7 +4711,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
        isec = msq->q_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = msq->q_perm.key;
+       ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
@@ -4658,7 +4748,7 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
        int err;
        int perms;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case MSG_INFO:
                /* No specific object, just general system-wide information. */
@@ -4742,7 +4832,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
        msec = msg->security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = msq->q_perm.key;
+       ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid,
                          SECCLASS_MSGQ, MSGQ__READ, &ad);
@@ -4768,7 +4858,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
        isec = shp->shm_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = shp->shm_perm.key;
+       ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
@@ -4806,7 +4896,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
        int perms;
        int err;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SHM_INFO:
                /* No specific object, just general system-wide information. */
@@ -4867,7 +4957,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
        isec = sma->sem_perm.security;
 
        AVC_AUDIT_DATA_INIT(&ad, IPC);
-       ad.u.ipc_id = sma->sem_perm.key;
+       ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
@@ -4905,7 +4995,7 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd)
        int err;
        u32 perms;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SEM_INFO:
                /* No specific object, just general system-wide information. */
@@ -4970,25 +5060,31 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
        return ipc_has_perm(ipcp, av);
 }
 
+static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+       struct ipc_security_struct *isec = ipcp->security;
+       *secid = isec->sid;
+}
+
 /* module stacking operations */
-static 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_ERR "%s:  There is already a secondary security "
-                      "module registered.\n", __FUNCTION__);
+                      "module registered.\n", __func__);
                return -EINVAL;
-       }
+       }
 
        secondary_ops = ops;
 
        printk(KERN_INFO "%s:  Registering secondary module %s\n",
-              __FUNCTION__,
+              __func__,
               name);
 
        return 0;
 }
 
-static void selinux_d_instantiate (struct dentry *dentry, struct inode *inode)
+static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 {
        if (inode)
                inode_doinit_with_dentry(inode, dentry);
@@ -5038,6 +5134,7 @@ static int selinux_setprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
+       struct task_struct *tracer;
        u32 sid = 0;
        int error;
        char *str = value;
@@ -5075,6 +5172,12 @@ static int selinux_setprocattr(struct task_struct *p,
                        size--;
                }
                error = security_context_to_sid(value, size, &sid);
+               if (error == -EINVAL && !strcmp(name, "fscreate")) {
+                       if (!capable(CAP_MAC_ADMIN))
+                               return error;
+                       error = security_context_to_sid_force(value, size,
+                                                             &sid);
+               }
                if (error)
                        return error;
        }
@@ -5115,34 +5218,39 @@ static int selinux_setprocattr(struct task_struct *p,
                                }
                        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);
+                                    PROCESS__DYNTRANSITION, NULL);
                if (error)
                        return error;
 
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and fail. */
                task_lock(p);
-               if (p->ptrace & PT_PTRACED) {
-                       error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
+               rcu_read_lock();
+               tracer = task_tracer_task(p);
+               if (tracer != NULL) {
+                       struct task_security_struct *ptsec = tracer->security;
+                       u32 ptsid = ptsec->sid;
+                       rcu_read_unlock();
+                       error = avc_has_perm_noaudit(ptsid, sid,
                                                     SECCLASS_PROCESS,
                                                     PROCESS__PTRACE, 0, &avd);
                        if (!error)
                                tsec->sid = sid;
                        task_unlock(p);
-                       avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS,
+                       avc_audit(ptsid, sid, SECCLASS_PROCESS,
                                  PROCESS__PTRACE, &avd, error, NULL);
                        if (error)
                                return error;
                } else {
+                       rcu_read_unlock();
                        tsec->sid = sid;
                        task_unlock(p);
                }
-       }
-       else
+       } else
                return -EINVAL;
 
        return size;
@@ -5153,7 +5261,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
        return security_sid_to_context(secid, secdata, seclen);
 }
 
-static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
        return security_context_to_sid(secdata, seclen, secid);
 }
@@ -5175,7 +5283,6 @@ static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
        if (!ksec)
                return -ENOMEM;
 
-       ksec->obj = k;
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
@@ -5216,9 +5323,25 @@ static int selinux_key_permission(key_ref_t key_ref,
                            SECCLASS_KEY, perm, NULL);
 }
 
+static int selinux_key_getsecurity(struct key *key, char **_buffer)
+{
+       struct key_security_struct *ksec = key->security;
+       char *context = NULL;
+       unsigned len;
+       int rc;
+
+       rc = security_sid_to_context(ksec->sid, &context, &len);
+       if (!rc)
+               rc = len;
+       *_buffer = context;
+       return rc;
+}
+
 #endif
 
 static struct security_operations selinux_ops = {
+       .name =                         "selinux",
+
        .ptrace =                       selinux_ptrace,
        .capget =                       selinux_capget,
        .capset_check =                 selinux_capset_check,
@@ -5231,7 +5354,7 @@ static struct security_operations selinux_ops = {
        .vm_enough_memory =             selinux_vm_enough_memory,
 
        .netlink_send =                 selinux_netlink_send,
-        .netlink_recv =                        selinux_netlink_recv,
+       .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_alloc_security =          selinux_bprm_alloc_security,
        .bprm_free_security =           selinux_bprm_free_security,
@@ -5244,13 +5367,15 @@ static struct security_operations selinux_ops = {
        .sb_alloc_security =            selinux_sb_alloc_security,
        .sb_free_security =             selinux_sb_free_security,
        .sb_copy_data =                 selinux_sb_copy_data,
-       .sb_kern_mount =                selinux_sb_kern_mount,
+       .sb_kern_mount =                selinux_sb_kern_mount,
        .sb_statfs =                    selinux_sb_statfs,
        .sb_mount =                     selinux_mount,
        .sb_umount =                    selinux_umount,
        .sb_get_mnt_opts =              selinux_get_mnt_opts,
        .sb_set_mnt_opts =              selinux_set_mnt_opts,
-       .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
+       .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
+       .sb_parse_opts_str =            selinux_parse_opts_str,
+
 
        .inode_alloc_security =         selinux_inode_alloc_security,
        .inode_free_security =          selinux_inode_free_security,
@@ -5273,11 +5398,12 @@ static struct security_operations selinux_ops = {
        .inode_getxattr =               selinux_inode_getxattr,
        .inode_listxattr =              selinux_inode_listxattr,
        .inode_removexattr =            selinux_inode_removexattr,
-       .inode_getsecurity =            selinux_inode_getsecurity,
-       .inode_setsecurity =            selinux_inode_setsecurity,
-       .inode_listsecurity =           selinux_inode_listsecurity,
+       .inode_getsecurity =            selinux_inode_getsecurity,
+       .inode_setsecurity =            selinux_inode_setsecurity,
+       .inode_listsecurity =           selinux_inode_listsecurity,
        .inode_need_killpriv =          selinux_inode_need_killpriv,
        .inode_killpriv =               selinux_inode_killpriv,
+       .inode_getsecid =               selinux_inode_getsecid,
 
        .file_permission =              selinux_file_permission,
        .file_alloc_security =          selinux_file_alloc_security,
@@ -5291,7 +5417,7 @@ static struct security_operations selinux_ops = {
        .file_send_sigiotask =          selinux_file_send_sigiotask,
        .file_receive =                 selinux_file_receive,
 
-       .dentry_open =                  selinux_dentry_open,
+       .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
        .task_alloc_security =          selinux_task_alloc_security,
@@ -5301,7 +5427,7 @@ static struct security_operations selinux_ops = {
        .task_setgid =                  selinux_task_setgid,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
-       .task_getsid =                  selinux_task_getsid,
+       .task_getsid =                  selinux_task_getsid,
        .task_getsecid =                selinux_task_getsecid,
        .task_setgroups =               selinux_task_setgroups,
        .task_setnice =                 selinux_task_setnice,
@@ -5315,9 +5441,10 @@ static struct security_operations selinux_ops = {
        .task_wait =                    selinux_task_wait,
        .task_prctl =                   selinux_task_prctl,
        .task_reparent_to_init =        selinux_task_reparent_to_init,
-       .task_to_inode =                selinux_task_to_inode,
+       .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
+       .ipc_getsecid =                 selinux_ipc_getsecid,
 
        .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
        .msg_msg_free_security =        selinux_msg_msg_free_security,
@@ -5335,24 +5462,24 @@ static struct security_operations selinux_ops = {
        .shm_shmctl =                   selinux_shm_shmctl,
        .shm_shmat =                    selinux_shm_shmat,
 
-       .sem_alloc_security =           selinux_sem_alloc_security,
-       .sem_free_security =            selinux_sem_free_security,
+       .sem_alloc_security =           selinux_sem_alloc_security,
+       .sem_free_security =            selinux_sem_free_security,
        .sem_associate =                selinux_sem_associate,
        .sem_semctl =                   selinux_sem_semctl,
        .sem_semop =                    selinux_sem_semop,
 
        .register_security =            selinux_register_security,
 
-       .d_instantiate =                selinux_d_instantiate,
+       .d_instantiate =                selinux_d_instantiate,
 
-       .getprocattr =                  selinux_getprocattr,
-       .setprocattr =                  selinux_setprocattr,
+       .getprocattr =                  selinux_getprocattr,
+       .setprocattr =                  selinux_setprocattr,
 
        .secid_to_secctx =              selinux_secid_to_secctx,
        .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
 
-        .unix_stream_connect =         selinux_socket_unix_stream_connect,
+       .unix_stream_connect =          selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
 
        .socket_create =                selinux_socket_create,
@@ -5374,7 +5501,7 @@ static struct security_operations selinux_ops = {
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_clone_security =            selinux_sk_clone_security,
-       .sk_getsecid =                  selinux_sk_getsecid,
+       .sk_getsecid =                  selinux_sk_getsecid,
        .sock_graft =                   selinux_sock_graft,
        .inet_conn_request =            selinux_inet_conn_request,
        .inet_csk_clone =               selinux_inet_csk_clone,
@@ -5389,15 +5516,23 @@ static struct security_operations selinux_ops = {
        .xfrm_state_alloc_security =    selinux_xfrm_state_alloc,
        .xfrm_state_free_security =     selinux_xfrm_state_free,
        .xfrm_state_delete_security =   selinux_xfrm_state_delete,
-       .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
+       .xfrm_policy_lookup =           selinux_xfrm_policy_lookup,
        .xfrm_state_pol_flow_match =    selinux_xfrm_state_pol_flow_match,
        .xfrm_decode_session =          selinux_xfrm_decode_session,
 #endif
 
 #ifdef CONFIG_KEYS
-       .key_alloc =                    selinux_key_alloc,
-       .key_free =                     selinux_key_free,
-       .key_permission =               selinux_key_permission,
+       .key_alloc =                    selinux_key_alloc,
+       .key_free =                     selinux_key_free,
+       .key_permission =               selinux_key_permission,
+       .key_getsecurity =              selinux_key_getsecurity,
+#endif
+
+#ifdef CONFIG_AUDIT
+       .audit_rule_init =              selinux_audit_rule_init,
+       .audit_rule_known =             selinux_audit_rule_known,
+       .audit_rule_match =             selinux_audit_rule_match,
+       .audit_rule_free =              selinux_audit_rule_free,
 #endif
 };
 
@@ -5405,6 +5540,11 @@ static __init int selinux_init(void)
 {
        struct task_security_struct *tsec;
 
+       if (!security_module_enable(&selinux_ops)) {
+               selinux_enabled = 0;
+               return 0;
+       }
+
        if (!selinux_enabled) {
                printk(KERN_INFO "SELinux:  Disabled at boot.\n");
                return 0;
@@ -5425,23 +5565,14 @@ static __init int selinux_init(void)
 
        original_ops = secondary_ops = security_ops;
        if (!secondary_ops)
-               panic ("SELinux: No initial security operations\n");
-       if (register_security (&selinux_ops))
+               panic("SELinux: No initial security operations\n");
+       if (register_security(&selinux_ops))
                panic("SELinux: Unable to register with kernel.\n");
 
-       if (selinux_enforcing) {
+       if (selinux_enforcing)
                printk(KERN_DEBUG "SELinux:  Starting in enforcing mode\n");
-       } else {
+       else
                printk(KERN_DEBUG "SELinux:  Starting in permissive mode\n");
-       }
-
-#ifdef CONFIG_KEYS
-       /* Add security information to initial keyrings */
-       selinux_key_alloc(&root_user_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-       selinux_key_alloc(&root_session_keyring, current,
-                         KEY_ALLOC_NOT_IN_QUOTA);
-#endif
 
        return 0;
 }
@@ -5458,8 +5589,8 @@ next_sb:
        if (!list_empty(&superblock_security_head)) {
                struct superblock_security_struct *sbsec =
                                list_entry(superblock_security_head.next,
-                                          struct superblock_security_struct,
-                                          list);
+                                          struct superblock_security_struct,
+                                          list);
                struct super_block *sb = sbsec->sb;
                sb->s_count++;
                spin_unlock(&sb_security_lock);
@@ -5578,10 +5709,11 @@ static void selinux_nf_ip_exit(void)
 #endif /* CONFIG_NETFILTER */
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
+static int selinux_disabled;
+
 int selinux_disable(void)
 {
        extern void exit_sel_fs(void);
-       static int selinux_disabled = 0;
 
        if (ss_initialized) {
                /* Not permitted after initial policy load. */
@@ -5610,5 +5742,3 @@ int selinux_disable(void)
        return 0;
 }
 #endif
-
-