Merge branch 'for-linus' of git://selinuxproject.org/~jmorris/linux-security
[linux-flexiantxendom0-3.2.10.git] / security / selinux / hooks.c
index 6f637d2..6a3683e 100644 (file)
@@ -14,7 +14,7 @@
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
  *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
- *     Paul Moore <paul.moore@hp.com>
+ *     Paul Moore <paul@paul-moore.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
  */
 
 #include <linux/init.h>
+#include <linux/kd.h>
 #include <linux/kernel.h>
 #include <linux/tracehook.h>
 #include <linux/errno.h>
+#include <linux/ext2_fs.h>
 #include <linux/sched.h>
 #include <linux/security.h>
 #include <linux/xattr.h>
 #include <linux/mman.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/proc_fs.h>
 #include <linux/swap.h>
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
+#include <linux/dcache.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
-#include <linux/proc_fs.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
@@ -54,7 +57,7 @@
 #include <net/netlabel.h>
 #include <linux/uaccess.h>
 #include <asm/ioctls.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>   /* for network interface checks */
 #include <net/ipv6.h>
 #include <linux/hugetlb.h>
 #include <linux/personality.h>
-#include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/string.h>
 #include <linux/selinux.h>
 #include <linux/mutex.h>
 #include <linux/posix-timers.h>
 #include <linux/syslog.h>
+#include <linux/user_namespace.h>
+#include <linux/export.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "xfrm.h"
 #include "netlabel.h"
 #include "audit.h"
+#include "avc_ss.h"
 
 #define NUM_SEL_MNT_OPTS 5
 
-extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 extern struct security_operations *security_ops;
 
 /* SECMARK reference count */
-atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
+static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing;
@@ -276,10 +280,6 @@ static void superblock_free_security(struct super_block *sb)
        kfree(sbsec);
 }
 
-/* The security server must be initialized before
-   any labeling or access decisions can be provided. */
-extern int ss_initialized;
-
 /* The file system's label must be initialized prior to use. */
 
 static const char *labeling_behaviors[6] = {
@@ -987,6 +987,7 @@ static void selinux_write_opts(struct seq_file *m,
                        continue;
                default:
                        BUG();
+                       return;
                };
                /* we need a comma before each option */
                seq_putc(m, ',');
@@ -1089,7 +1090,7 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                        return SECCLASS_NETLINK_ROUTE_SOCKET;
                case NETLINK_FIREWALL:
                        return SECCLASS_NETLINK_FIREWALL_SOCKET;
-               case NETLINK_INET_DIAG:
+               case NETLINK_SOCK_DIAG:
                        return SECCLASS_NETLINK_TCPDIAG_SOCKET;
                case NETLINK_NFLOG:
                        return SECCLASS_NETLINK_NFLOG_SOCKET;
@@ -1120,39 +1121,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
 }
 
 #ifdef CONFIG_PROC_FS
-static int selinux_proc_get_sid(struct proc_dir_entry *de,
+static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
 {
-       int buflen, rc;
-       char *buffer, *path, *end;
+       int rc;
+       char *buffer, *path;
 
        buffer = (char *)__get_free_page(GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (de && de != de->parent) {
-               buflen -= de->namelen + 1;
-               if (buflen < 0)
-                       break;
-               end -= de->namelen;
-               memcpy(end, de->name, de->namelen);
-               *--end = '/';
-               path = end;
-               de = de->parent;
+       path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
+       if (IS_ERR(path))
+               rc = PTR_ERR(path);
+       else {
+               /* each process gets a /proc/PID/ entry. Strip off the
+                * PID part to get a valid selinux labeling.
+                * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+               while (path[1] >= '0' && path[1] <= '9') {
+                       path[1] = '/';
+                       path++;
+               }
+               rc = security_genfs_sid("proc", path, tclass, sid);
        }
-       rc = security_genfs_sid("proc", path, tclass, sid);
        free_page((unsigned long)buffer);
        return rc;
 }
 #else
-static int selinux_proc_get_sid(struct proc_dir_entry *de,
+static int selinux_proc_get_sid(struct dentry *dentry,
                                u16 tclass,
                                u32 *sid)
 {
@@ -1300,10 +1297,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
                /* Try to obtain a transition SID. */
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-               rc = security_transition_sid(isec->task_sid,
-                                            sbsec->sid,
-                                            isec->sclass,
-                                            &sid);
+               rc = security_transition_sid(isec->task_sid, sbsec->sid,
+                                            isec->sclass, NULL, &sid);
                if (rc)
                        goto out_unlock;
                isec->sid = sid;
@@ -1316,10 +1311,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                isec->sid = sbsec->sid;
 
                if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
-                       struct proc_inode *proci = PROC_I(inode);
-                       if (proci->pde) {
+                       if (opt_dentry) {
                                isec->sclass = inode_mode_to_security_class(inode->i_mode);
-                               rc = selinux_proc_get_sid(proci->pde,
+                               rc = selinux_proc_get_sid(opt_dentry,
                                                          isec->sclass,
                                                          &sid);
                                if (rc)
@@ -1421,8 +1415,7 @@ static int current_has_perm(const struct task_struct *tsk,
 #endif
 
 /* Check whether a task is allowed to use a capability. */
-static int task_has_capability(struct task_struct *tsk,
-                              const struct cred *cred,
+static int cred_has_capability(const struct cred *cred,
                               int cap, int audit)
 {
        struct common_audit_data ad;
@@ -1433,7 +1426,7 @@ static int task_has_capability(struct task_struct *tsk,
        int rc;
 
        COMMON_AUDIT_DATA_INIT(&ad, CAP);
-       ad.tsk = tsk;
+       ad.tsk = current;
        ad.u.cap = cap;
 
        switch (CAP_TO_INDEX(cap)) {
@@ -1447,11 +1440,15 @@ static int task_has_capability(struct task_struct *tsk,
                printk(KERN_ERR
                       "SELinux:  out of range capability %d\n", cap);
                BUG();
+               return -EINVAL;
        }
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
-       if (audit == SECURITY_CAP_AUDIT)
-               avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+       if (audit == SECURITY_CAP_AUDIT) {
+               int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+               if (rc2)
+                       return rc2;
+       }
        return rc;
 }
 
@@ -1471,10 +1468,10 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct common_audit_data *adp)
+                         struct common_audit_data *adp,
+                         unsigned flags)
 {
        struct inode_security_struct *isec;
-       struct common_audit_data ad;
        u32 sid;
 
        validate_creds(cred);
@@ -1485,30 +1482,49 @@ static int inode_has_perm(const struct cred *cred,
        sid = cred_sid(cred);
        isec = inode->i_security;
 
-       if (!adp) {
-               adp = &ad;
-               COMMON_AUDIT_DATA_INIT(&ad, FS);
-               ad.u.fs.inode = inode;
-       }
+       return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
+}
+
+static int inode_has_perm_noadp(const struct cred *cred,
+                               struct inode *inode,
+                               u32 perms,
+                               unsigned flags)
+{
+       struct common_audit_data ad;
 
-       return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.u.inode = inode;
+       return inode_has_perm(cred, inode, perms, &ad, flags);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
 static inline int dentry_has_perm(const struct cred *cred,
-                                 struct vfsmount *mnt,
                                  struct dentry *dentry,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.mnt = mnt;
-       ad.u.fs.path.dentry = dentry;
-       return inode_has_perm(cred, inode, av, &ad);
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
+       return inode_has_perm(cred, inode, av, &ad, 0);
+}
+
+/* Same as inode_has_perm, but pass explicit audit data containing
+   the path to help the auditing code to more easily generate the
+   pathname if needed. */
+static inline int path_has_perm(const struct cred *cred,
+                               struct path *path,
+                               u32 av)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct common_audit_data ad;
+
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = *path;
+       return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
 /* Check whether a task can use an open file descriptor to
@@ -1529,8 +1545,8 @@ static int file_has_perm(const struct cred *cred,
        u32 sid = cred_sid(cred);
        int rc;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = file->f_path;
 
        if (sid != fsec->sid) {
                rc = avc_has_perm(sid, fsec->sid,
@@ -1544,7 +1560,7 @@ static int file_has_perm(const struct cred *cred,
        /* av is zero if only checking access to the descriptor. */
        rc = 0;
        if (av)
-               rc = inode_has_perm(cred, inode, av, &ad);
+               rc = inode_has_perm(cred, inode, av, &ad, 0);
 
 out:
        return rc;
@@ -1568,8 +1584,8 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
@@ -1578,7 +1594,8 @@ static int may_create(struct inode *dir,
                return rc;
 
        if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
-               rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
+               rc = security_transition_sid(sid, dsec->sid, tclass,
+                                            &dentry->d_name, &newsid);
                if (rc)
                        return rc;
        }
@@ -1620,8 +1637,8 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1666,9 +1683,9 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 
-       ad.u.fs.path.dentry = old_dentry;
+       ad.u.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
                          DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
@@ -1684,7 +1701,7 @@ static inline int may_rename(struct inode *old_dir,
                        return rc;
        }
 
-       ad.u.fs.path.dentry = new_dentry;
+       ad.u.dentry = new_dentry;
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (new_dentry->d_inode)
                av |= DIR__REMOVE_NAME;
@@ -1722,7 +1739,7 @@ static inline u32 file_mask_to_av(int mode, int mask)
 {
        u32 av = 0;
 
-       if ((mode & S_IFMT) != S_IFDIR) {
+       if (!S_ISDIR(mode)) {
                if (mask & MAY_EXEC)
                        av |= FILE__EXECUTE;
                if (mask & MAY_READ)
@@ -1793,7 +1810,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
        if (rc)
                return rc;
 
-       if (mode == PTRACE_MODE_READ) {
+       if (mode & PTRACE_MODE_READ) {
                u32 sid = current_sid();
                u32 csid = task_sid(child);
                return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
@@ -1850,92 +1867,16 @@ static int selinux_capset(struct cred *new, const struct cred *old,
  * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
  */
 
-static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
+static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
                           int cap, int audit)
 {
        int rc;
 
-       rc = cap_capable(tsk, cred, cap, audit);
+       rc = cap_capable(cred, ns, cap, audit);
        if (rc)
                return rc;
 
-       return task_has_capability(tsk, cred, cap, audit);
-}
-
-static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
-{
-       int buflen, rc;
-       char *buffer, *path, *end;
-
-       rc = -ENOMEM;
-       buffer = (char *)__get_free_page(GFP_KERNEL);
-       if (!buffer)
-               goto out;
-
-       buflen = PAGE_SIZE;
-       end = buffer+buflen;
-       *--end = '\0';
-       buflen--;
-       path = end-1;
-       *path = '/';
-       while (table) {
-               const char *name = table->procname;
-               size_t namelen = strlen(name);
-               buflen -= namelen + 1;
-               if (buflen < 0)
-                       goto out_free;
-               end -= namelen;
-               memcpy(end, name, namelen);
-               *--end = '/';
-               path = end;
-               table = table->parent;
-       }
-       buflen -= 4;
-       if (buflen < 0)
-               goto out_free;
-       end -= 4;
-       memcpy(end, "/sys", 4);
-       path = end;
-       rc = security_genfs_sid("proc", path, tclass, sid);
-out_free:
-       free_page((unsigned long)buffer);
-out:
-       return rc;
-}
-
-static int selinux_sysctl(ctl_table *table, int op)
-{
-       int error = 0;
-       u32 av;
-       u32 tsid, sid;
-       int rc;
-
-       sid = current_sid();
-
-       rc = selinux_sysctl_get_sid(table, (op == 0001) ?
-                                   SECCLASS_DIR : SECCLASS_FILE, &tsid);
-       if (rc) {
-               /* Default to the well-defined sysctl SID. */
-               tsid = SECINITSID_SYSCTL;
-       }
-
-       /* The op values are "defined" in sysctl.c, thereby creating
-        * a bad coupling between this module and sysctl.c */
-       if (op == 001) {
-               error = avc_has_perm(sid, tsid,
-                                    SECCLASS_DIR, DIR__SEARCH, NULL);
-       } else {
-               av = 0;
-               if (op & 004)
-                       av |= FILE__READ;
-               if (op & 002)
-                       av |= FILE__WRITE;
-               if (av)
-                       error = avc_has_perm(sid, tsid,
-                                            SECCLASS_FILE, av, NULL);
-       }
-
-       return error;
+       return cred_has_capability(cred, cap, audit);
 }
 
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -1970,7 +1911,7 @@ static int selinux_quota_on(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
+       return dentry_has_perm(cred, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -2012,7 +1953,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
 
-       rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
+       rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
                             SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
@@ -2060,13 +2001,14 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(old_tsec->sid, isec->sid,
-                                            SECCLASS_PROCESS, &new_tsec->sid);
+                                            SECCLASS_PROCESS, NULL,
+                                            &new_tsec->sid);
                if (rc)
                        return rc;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = bprm->file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                new_tsec->sid = old_tsec->sid;
@@ -2106,7 +2048,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        u32 ptsid = 0;
 
                        rcu_read_lock();
-                       tracer = tracehook_tracer_task(current);
+                       tracer = ptrace_parent(current);
                        if (likely(tracer != NULL)) {
                                sec = __task_cred(tracer)->security;
                                ptsid = sec->sid;
@@ -2150,9 +2092,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
        return (atsecure || cap_bprm_secureexec(bprm));
 }
 
-extern struct vfsmount *selinuxfs_mount;
-extern struct dentry *selinux_null;
-
 /* Derived from fs/exec.c:flush_old_files. */
 static inline void flush_unauthorized_files(const struct cred *cred,
                                            struct files_struct *files)
@@ -2180,8 +2119,8 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                                                struct tty_file_private, list);
                        file = file_priv->file;
                        inode = file->f_path.dentry->d_inode;
-                       if (inode_has_perm(cred, inode,
-                                          FILE__READ | FILE__WRITE, NULL)) {
+                       if (inode_has_perm_noadp(cred, inode,
+                                          FILE__READ | FILE__WRITE, 0)) {
                                drop_tty = 1;
                        }
                }
@@ -2194,7 +2133,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2443,6 +2382,91 @@ out:
        return rc;
 }
 
+static int selinux_sb_remount(struct super_block *sb, void *data)
+{
+       int rc, i, *flags;
+       struct security_mnt_opts opts;
+       char *secdata, **mount_options;
+       struct superblock_security_struct *sbsec = sb->s_security;
+
+       if (!(sbsec->flags & SE_SBINITIALIZED))
+               return 0;
+
+       if (!data)
+               return 0;
+
+       if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+               return 0;
+
+       security_init_mnt_opts(&opts);
+       secdata = alloc_secdata();
+       if (!secdata)
+               return -ENOMEM;
+       rc = selinux_sb_copy_data(data, secdata);
+       if (rc)
+               goto out_free_secdata;
+
+       rc = selinux_parse_opts_str(secdata, &opts);
+       if (rc)
+               goto out_free_secdata;
+
+       mount_options = opts.mnt_opts;
+       flags = opts.mnt_opts_flags;
+
+       for (i = 0; i < opts.num_mnt_opts; i++) {
+               u32 sid;
+               size_t len;
+
+               if (flags[i] == SE_SBLABELSUPP)
+                       continue;
+               len = strlen(mount_options[i]);
+               rc = security_context_to_sid(mount_options[i], len, &sid);
+               if (rc) {
+                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                              "(%s) failed for (dev %s, type %s) errno=%d\n",
+                              mount_options[i], sb->s_id, sb->s_type->name, rc);
+                       goto out_free_opts;
+               }
+               rc = -EINVAL;
+               switch (flags[i]) {
+               case FSCONTEXT_MNT:
+                       if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+                               goto out_bad_option;
+                       break;
+               case CONTEXT_MNT:
+                       if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+                               goto out_bad_option;
+                       break;
+               case ROOTCONTEXT_MNT: {
+                       struct inode_security_struct *root_isec;
+                       root_isec = sb->s_root->d_inode->i_security;
+
+                       if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+                               goto out_bad_option;
+                       break;
+               }
+               case DEFCONTEXT_MNT:
+                       if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+                               goto out_bad_option;
+                       break;
+               default:
+                       goto out_free_opts;
+               }
+       }
+
+       rc = 0;
+out_free_opts:
+       security_free_mnt_opts(&opts);
+out_free_secdata:
+       free_secdata(secdata);
+       return rc;
+out_bad_option:
+       printk(KERN_WARNING "SELinux: unable to change security options "
+              "during remount (dev %s, type=%s)\n", sb->s_id,
+              sb->s_type->name);
+       goto out_free_opts;
+}
+
 static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
        const struct cred *cred = current_cred();
@@ -2457,8 +2481,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
 
@@ -2467,8 +2491,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
        const struct cred *cred = current_cred();
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry->d_sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
@@ -2481,11 +2505,10 @@ static int selinux_mount(char *dev_name,
        const struct cred *cred = current_cred();
 
        if (flags & MS_REMOUNT)
-               return superblock_has_perm(cred, path->mnt->mnt_sb,
+               return superblock_has_perm(cred, path->dentry->d_sb,
                                           FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(cred, path->mnt, path->dentry,
-                                      FILE__MOUNTON);
+               return path_has_perm(cred, path, FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2509,8 +2532,8 @@ static void selinux_inode_free_security(struct inode *inode)
 }
 
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
-                                      char **name, void **value,
-                                      size_t *len)
+                                      const struct qstr *qstr, char **name,
+                                      void **value, size_t *len)
 {
        const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
@@ -2525,10 +2548,13 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
+       if ((sbsec->flags & SE_SBINITIALIZED) &&
+           (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
+               newsid = sbsec->mntpoint_sid;
+       else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
                rc = security_transition_sid(sid, dsec->sid,
                                             inode_mode_to_security_class(inode->i_mode),
-                                            &newsid);
+                                            qstr, &newsid);
                if (rc) {
                        printk(KERN_WARNING "%s:  "
                               "security_transition_sid failed, rc=%d (dev=%s "
@@ -2570,7 +2596,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        return 0;
 }
 
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        return may_create(dir, dentry, SECCLASS_FILE);
 }
@@ -2590,7 +2616,7 @@ static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const
        return may_create(dir, dentry, SECCLASS_LNK_FILE);
 }
 
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
 {
        return may_create(dir, dentry, SECCLASS_DIR);
 }
@@ -2600,7 +2626,7 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
        return may_link(dir, dentry, MAY_RMDIR);
 }
 
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 {
        return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
@@ -2615,14 +2641,14 @@ static int selinux_inode_readlink(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask)
@@ -2631,6 +2657,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        struct common_audit_data ad;
        u32 perms;
        bool from_access;
+       unsigned flags = mask & MAY_NOT_BLOCK;
 
        from_access = mask & MAY_ACCESS;
        mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
@@ -2639,15 +2666,15 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (!mask)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.inode = inode;
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.u.inode = inode;
 
        if (from_access)
                ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
 
        perms = file_mask_to_av(inode->i_mode, mask);
 
-       return inode_has_perm(cred, inode, perms, &ad);
+       return inode_has_perm(cred, inode, perms, &ad, flags);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2665,16 +2692,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
-               return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+               return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
+       return dentry_has_perm(cred, dentry, FILE__WRITE);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
+       struct path path;
+
+       path.dentry = dentry;
+       path.mnt = mnt;
 
-       return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
+       return path_has_perm(cred, &path, FILE__GETATTR);
 }
 
 static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@@ -2695,7 +2726,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 
        /* Not an attribute we recognize, so just check the
           ordinary setattr permission. */
-       return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+       return dentry_has_perm(cred, dentry, FILE__SETATTR);
 }
 
 static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@@ -2715,11 +2746,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
@@ -2782,14 +2813,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_listxattr(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -2826,7 +2857,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
+       error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
                                SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
@@ -2929,16 +2960,47 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
        const struct cred *cred = current_cred();
-       u32 av = 0;
+       int error = 0;
 
-       if (_IOC_DIR(cmd) & _IOC_WRITE)
-               av |= FILE__WRITE;
-       if (_IOC_DIR(cmd) & _IOC_READ)
-               av |= FILE__READ;
-       if (!av)
-               av = FILE__IOCTL;
+       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(cred, file, FILE__GETATTR);
+               break;
 
-       return file_has_perm(cred, file, av);
+       case EXT2_IOC_SETFLAGS:
+       /* fall through */
+       case EXT2_IOC_SETVERSION:
+               error = file_has_perm(cred, file, FILE__SETATTR);
+               break;
+
+       /* sys_ioctl() checks */
+       case FIONBIO:
+       /* fall through */
+       case FIOASYNC:
+               error = file_has_perm(cred, file, 0);
+               break;
+
+       case KDSKBENT:
+       case KDSKBSENT:
+               error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
+                                           SECURITY_CAP_AUDIT);
+               break;
+
+       /* default case assumes that the command will go
+        * to the file's ioctl() function.
+        */
+       default:
+               error = file_has_perm(cred, file, FILE__IOCTL);
+       }
+       return error;
 }
 
 static int default_noexec;
@@ -3163,7 +3225,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
+       return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
 }
 
 /* task security operations */
@@ -3195,7 +3257,11 @@ static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
 
-       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       /*
+        * cred->security == NULL if security_cred_alloc_blank() or
+        * security_prepare_creds() returned an error.
+        */
+       BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
        cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
@@ -3492,19 +3558,20 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
        u8 nexthdr;
        int ret = -EINVAL, offset;
        struct ipv6hdr _ipv6h, *ip6;
+       __be16 frag_off;
 
        offset = skb_network_offset(skb);
        ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
        if (ip6 == NULL)
                goto out;
 
-       ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
-       ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+       ad->u.net.v6info.saddr = ip6->saddr;
+       ad->u.net.v6info.daddr = ip6->daddr;
        ret = 0;
 
        nexthdr = ip6->nexthdr;
        offset += sizeof(_ipv6h);
-       offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+       offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
        if (offset < 0)
                goto out;
 
@@ -3637,9 +3704,16 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
 
 /* socket security operations */
 
-static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
+static int socket_sockcreate_sid(const struct task_security_struct *tsec,
+                                u16 secclass, u32 *socksid)
 {
-       return tsec->sockcreate_sid ? : tsec->sid;
+       if (tsec->sockcreate_sid > SECSID_NULL) {
+               *socksid = tsec->sockcreate_sid;
+               return 0;
+       }
+
+       return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
+                                      socksid);
 }
 
 static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
@@ -3663,12 +3737,16 @@ static int selinux_socket_create(int family, int type,
        const struct task_security_struct *tsec = current_security();
        u32 newsid;
        u16 secclass;
+       int rc;
 
        if (kern)
                return 0;
 
-       newsid = socket_sockcreate_sid(tsec);
        secclass = socket_type_to_security_class(family, type, protocol);
+       rc = socket_sockcreate_sid(tsec, secclass, &newsid);
+       if (rc)
+               return rc;
+
        return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
 }
 
@@ -3680,12 +3758,16 @@ static int selinux_socket_post_create(struct socket *sock, int family,
        struct sk_security_struct *sksec;
        int err = 0;
 
+       isec->sclass = socket_type_to_security_class(family, type, protocol);
+
        if (kern)
                isec->sid = SECINITSID_KERNEL;
-       else
-               isec->sid = socket_sockcreate_sid(tsec);
+       else {
+               err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
+               if (err)
+                       return err;
+       }
 
-       isec->sclass = socket_type_to_security_class(family, type, protocol);
        isec->initialized = 1;
 
        if (sock->sk) {
@@ -3787,7 +3869,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (family == PF_INET)
                        ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
                else
-                       ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
+                       ad.u.net.v6info.saddr = addr6->sin6_addr;
 
                err = avc_has_perm(sksec->sid, sid,
                                   sksec->sclass, node_perm, &ad);
@@ -3995,7 +4077,6 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 {
        int err = 0;
        struct sk_security_struct *sksec = sk->sk_security;
-       u32 peer_sid;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
        char *addrp;
@@ -4014,20 +4095,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                        return err;
        }
 
-       if (selinux_policycap_netpeer) {
-               err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
-               if (err)
-                       return err;
-               err = avc_has_perm(sk_sid, peer_sid,
-                                  SECCLASS_PEER, PEER__RECV, &ad);
-               if (err)
-                       selinux_netlbl_err(skb, err, 0);
-       } else {
-               err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
-               if (err)
-                       return err;
-               err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
-       }
+       err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
+       if (err)
+               return err;
+       err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
 
        return err;
 }
@@ -4299,7 +4370,7 @@ static void selinux_secmark_refcount_dec(void)
 static void selinux_req_classify_flow(const struct request_sock *req,
                                      struct flowi *fl)
 {
-       fl->secid = req->secid;
+       fl->flowi_secid = req->secid;
 }
 
 static int selinux_tun_dev_create(void)
@@ -4522,9 +4593,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                 SECCLASS_PACKET, PACKET__SEND, &ad))
                        return NF_DROP_ERR(-ECONNREFUSED);
 
-       if (selinux_policycap_netpeer)
-               if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
-                       return NF_DROP_ERR(-ECONNREFUSED);
+       if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
+               return NF_DROP_ERR(-ECONNREFUSED);
 
        return NF_ACCEPT;
 }
@@ -4567,27 +4637,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         * from the sending socket, otherwise use the kernel's sid */
        sk = skb->sk;
        if (sk == NULL) {
-               switch (family) {
-               case PF_INET:
-                       if (IPCB(skb)->flags & IPSKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               case PF_INET6:
-                       if (IP6CB(skb)->flags & IP6SKB_FORWARDED)
-                               secmark_perm = PACKET__FORWARD_OUT;
-                       else
-                               secmark_perm = PACKET__SEND;
-                       break;
-               default:
-                       return NF_DROP_ERR(-ECONNREFUSED);
-               }
-               if (secmark_perm == PACKET__FORWARD_OUT) {
+               if (skb->skb_iif) {
+                       secmark_perm = PACKET__FORWARD_OUT;
                        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
                                return NF_DROP;
-               } else
+               } else {
+                       secmark_perm = PACKET__SEND;
                        peer_sid = SECINITSID_KERNEL;
+               }
        } else {
                struct sk_security_struct *sksec = sk->sk_security;
                peer_sid = sksec->sid;
@@ -4658,22 +4715,6 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return selinux_nlmsg_perm(sk, skb);
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb, int capability)
-{
-       int err;
-       struct common_audit_data ad;
-
-       err = cap_netlink_recv(skb, capability);
-       if (err)
-               return err;
-
-       COMMON_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,
                              struct kern_ipc_perm *perm,
                              u16 sclass)
@@ -4841,7 +4882,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                 * message queue this message will be stored in
                 */
                rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
-                                            &msec->sid);
+                                            NULL, &msec->sid);
                if (rc)
                        return rc;
        }
@@ -5253,7 +5294,7 @@ static int selinux_setprocattr(struct task_struct *p,
                   Otherwise, leave SID unchanged and fail. */
                ptsid = 0;
                task_lock(p);
-               tracer = tracehook_tracer_task(p);
+               tracer = ptrace_parent(p);
                if (tracer)
                        ptsid = task_sid(tracer);
                task_unlock(p);
@@ -5395,7 +5436,6 @@ static struct security_operations selinux_ops = {
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
-       .sysctl =                       selinux_sysctl,
        .capable =                      selinux_capable,
        .quotactl =                     selinux_quotactl,
        .quota_on =                     selinux_quota_on,
@@ -5403,7 +5443,6 @@ static struct security_operations selinux_ops = {
        .vm_enough_memory =             selinux_vm_enough_memory,
 
        .netlink_send =                 selinux_netlink_send,
-       .netlink_recv =                 selinux_netlink_recv,
 
        .bprm_set_creds =               selinux_bprm_set_creds,
        .bprm_committing_creds =        selinux_bprm_committing_creds,
@@ -5413,6 +5452,7 @@ 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_remount =                   selinux_sb_remount,
        .sb_kern_mount =                selinux_sb_kern_mount,
        .sb_show_options =              selinux_sb_show_options,
        .sb_statfs =                    selinux_sb_statfs,
@@ -5736,8 +5776,6 @@ static int selinux_disabled;
 
 int selinux_disable(void)
 {
-       extern void exit_sel_fs(void);
-
        if (ss_initialized) {
                /* Not permitted after initial policy load. */
                return -EINVAL;