do_wait() wakeup optimization: change __wake_up_parent() to use filtered wakeup
[pandora-kernel.git] / security / selinux / hooks.c
index 8d8b69c..bb230d5 100644 (file)
@@ -13,8 +13,8 @@
  *                                        Eric Paris <eparis@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
- *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
- *             Paul Moore <paul.moore@hp.com>
+ *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
+ *     Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
@@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb)
            sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                sbsec->flags &= ~SE_SBLABELSUPP;
 
+       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
+       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+               sbsec->flags |= SE_SBLABELSUPP;
+
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
 
@@ -1479,14 +1483,14 @@ static int task_has_capability(struct task_struct *tsk,
                               const struct cred *cred,
                               int cap, int audit)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct av_decision avd;
        u16 sclass;
        u32 sid = cred_sid(cred);
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
@@ -1525,12 +1529,14 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct avc_audit_data *adp)
+                         struct common_audit_data *adp)
 {
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid;
 
+       validate_creds(cred);
+
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -1539,7 +1545,7 @@ static int inode_has_perm(const struct cred *cred,
 
        if (!adp) {
                adp = &ad;
-               AVC_AUDIT_DATA_INIT(&ad, FS);
+               COMMON_AUDIT_DATA_INIT(&ad, FS);
                ad.u.fs.inode = inode;
        }
 
@@ -1555,9 +1561,9 @@ static inline int dentry_has_perm(const struct cred *cred,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       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);
@@ -1577,11 +1583,11 @@ static int file_has_perm(const struct cred *cred,
 {
        struct file_security_struct *fsec = file->f_security;
        struct inode *inode = file->f_path.dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = cred_sid(cred);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = file->f_path;
 
        if (sid != fsec->sid) {
@@ -1612,7 +1618,7 @@ static int may_create(struct inode *dir,
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        dsec = dir->i_security;
@@ -1621,7 +1627,7 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
@@ -1665,7 +1671,7 @@ static int may_link(struct inode *dir,
 
 {
        struct inode_security_struct *dsec, *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int rc;
@@ -1673,7 +1679,7 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        av = DIR__SEARCH;
@@ -1708,7 +1714,7 @@ static inline int may_rename(struct inode *old_dir,
                             struct dentry *new_dentry)
 {
        struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int old_is_dir, new_is_dir;
@@ -1719,7 +1725,7 @@ 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;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        ad.u.fs.path.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
@@ -1761,7 +1767,7 @@ static inline int may_rename(struct inode *old_dir,
 static int superblock_has_perm(const struct cred *cred,
                               struct super_block *sb,
                               u32 perms,
-                              struct avc_audit_data *ad)
+                              struct common_audit_data *ad)
 {
        struct superblock_security_struct *sbsec;
        u32 sid = cred_sid(cred);
@@ -1855,12 +1861,12 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace_may_access(struct task_struct *child,
+static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
        int rc;
 
-       rc = cap_ptrace_may_access(child, mode);
+       rc = cap_ptrace_access_check(child, mode);
        if (rc)
                return rc;
 
@@ -2101,7 +2107,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        const struct task_security_struct *old_tsec;
        struct task_security_struct *new_tsec;
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct inode *inode = bprm->file->f_path.dentry->d_inode;
        int rc;
 
@@ -2139,7 +2145,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
@@ -2232,7 +2238,7 @@ extern struct dentry *selinux_null;
 static inline void flush_unauthorized_files(const struct cred *cred,
                                            struct files_struct *files)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct file *file, *devnull = NULL;
        struct tty_struct *tty;
        struct fdtable *fdt;
@@ -2266,7 +2272,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2405,7 +2411,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
        /* Wake up the parent if it is waiting so that it can recheck
         * wait permission to the new task SID. */
        read_lock(&tasklist_lock);
-       wake_up_interruptible(&current->real_parent->signal->wait_chldexit);
+       __wake_up_parent(current, current->real_parent);
        read_unlock(&tasklist_lock);
 }
 
@@ -2515,7 +2521,7 @@ out:
 static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        rc = superblock_doinit(sb, data);
@@ -2526,7 +2532,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2534,9 +2540,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 static int selinux_sb_statfs(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
@@ -2711,12 +2717,18 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
+       unsigned int ia_valid = iattr->ia_valid;
+
+       /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
+       if (ia_valid & ATTR_FORCE) {
+               ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
+                             ATTR_FORCE);
+               if (!ia_valid)
+                       return 0;
+       }
 
-       if (iattr->ia_valid & ATTR_FORCE)
-               return 0;
-
-       if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
-                              ATTR_ATIME_SET | ATTR_MTIME_SET))
+       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, NULL, dentry, FILE__WRITE);
@@ -2756,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 newsid, sid = current_sid();
        int rc = 0;
 
@@ -2770,7 +2782,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!is_owner_or_cap(inode))
                return -EPERM;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
@@ -2915,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                return rc;
 
        isec->sid = newsid;
+       isec->initialized = 1;
        return 0;
 }
 
@@ -2939,11 +2952,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
        const struct cred *cred = current_cred();
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
-               return 0;
-       }
-
        /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
@@ -2954,10 +2962,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
 
 static int selinux_file_permission(struct file *file, int mask)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct file_security_struct *fsec = file->f_security;
+       struct inode_security_struct *isec = inode->i_security;
+       u32 sid = current_sid();
+
        if (!mask)
                /* No permission to check.  Existence test. */
                return 0;
 
+       if (sid == fsec->sid && fsec->isid == isec->sid &&
+           fsec->pseqno == avc_policy_seqno())
+               /* No change since dentry_open check. */
+               return 0;
+
        return selinux_revalidate_file_permission(file, mask);
 }
 
@@ -3219,13 +3237,30 @@ static int selinux_task_create(unsigned long clone_flags)
        return current_has_perm(current, PROCESS__FORK);
 }
 
+/*
+ * allocate the SELinux part of blank credentials
+ */
+static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       struct task_security_struct *tsec;
+
+       tsec = kzalloc(sizeof(struct task_security_struct), gfp);
+       if (!tsec)
+               return -ENOMEM;
+
+       cred->security = tsec;
+       return 0;
+}
+
 /*
  * detach and free the LSM part of a set of credentials
  */
 static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
-       cred->security = NULL;
+
+       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
 
@@ -3248,6 +3283,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
+/*
+ * transfer the SELinux data to a blank set of creds
+ */
+static void selinux_cred_transfer(struct cred *new, const struct cred *old)
+{
+       const struct task_security_struct *old_tsec = old->security;
+       struct task_security_struct *tsec = new->security;
+
+       *tsec = *old_tsec;
+}
+
 /*
  * set the security data for a kernel service
  * - all the creation contexts are set to unlabelled
@@ -3292,6 +3338,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
        return 0;
 }
 
+static int selinux_kernel_module_request(void)
+{
+       return task_has_system(current, SYSTEM__MODULE_REQUEST);
+}
+
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return current_has_perm(p, PROCESS__SETPGID);
@@ -3409,7 +3460,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv4(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        int offset, ihlen, ret = -EINVAL;
        struct iphdr _iph, *ih;
@@ -3490,7 +3541,7 @@ out:
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv6(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        u8 nexthdr;
        int ret = -EINVAL, offset;
@@ -3561,7 +3612,7 @@ out:
 
 #endif /* IPV6 */
 
-static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
+static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
                             char **_addrp, int src, u8 *proto)
 {
        char *addrp;
@@ -3643,7 +3694,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
                           u32 perms)
 {
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid;
        int err = 0;
 
@@ -3653,7 +3704,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
                goto out;
        sid = task_sid(task);
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = sock->sk;
        err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 
@@ -3740,7 +3791,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
                struct inode_security_struct *isec;
-               struct avc_audit_data ad;
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
@@ -3769,7 +3820,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                                      snum, &sid);
                                if (err)
                                        goto out;
-                               AVC_AUDIT_DATA_INIT(&ad, NET);
+                               COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
                                err = avc_has_perm(isec->sid, sid,
@@ -3802,7 +3853,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (err)
                        goto out;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.sport = htons(snum);
                ad.u.net.family = family;
 
@@ -3836,7 +3887,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        isec = SOCK_INODE(sock)->i_security;
        if (isec->sclass == SECCLASS_TCP_SOCKET ||
            isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct avc_audit_data ad;
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
@@ -3861,7 +3912,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
                err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
@@ -3951,13 +4002,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
        struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int err;
 
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3983,13 +4034,13 @@ static int selinux_socket_unix_may_send(struct socket *sock,
 {
        struct inode_security_struct *isec;
        struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int err;
 
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -4002,7 +4053,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
                                    u32 peer_sid,
-                                   struct avc_audit_data *ad)
+                                   struct common_audit_data *ad)
 {
        int err;
        u32 if_sid;
@@ -4030,10 +4081,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
@@ -4071,7 +4122,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        struct sk_security_struct *sksec = sk->sk_security;
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4095,7 +4146,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!secmark_active && !peerlbl_active)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
@@ -4309,6 +4360,59 @@ static void selinux_req_classify_flow(const struct request_sock *req,
        fl->secid = req->secid;
 }
 
+static int selinux_tun_dev_create(void)
+{
+       u32 sid = current_sid();
+
+       /* we aren't taking into account the "sockcreate" SID since the socket
+        * that is being created here is not a socket in the traditional sense,
+        * instead it is a private sock, accessible only to the kernel, and
+        * representing a wide range of network traffic spanning multiple
+        * connections unlike traditional sockets - check the TUN driver to
+        * get a better understanding of why this socket is special */
+
+       return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+                           NULL);
+}
+
+static void selinux_tun_dev_post_create(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       /* we don't currently perform any NetLabel based labeling here and it
+        * isn't clear that we would want to do so anyway; while we could apply
+        * labeling without the support of the TUN user the resulting labeled
+        * traffic from the other end of the connection would almost certainly
+        * cause confusion to the TUN user that had no idea network labeling
+        * protocols were being used */
+
+       /* see the comments in selinux_tun_dev_create() about why we don't use
+        * the sockcreate SID here */
+
+       sksec->sid = current_sid();
+       sksec->sclass = SECCLASS_TUN_SOCKET;
+}
+
+static int selinux_tun_dev_attach(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       u32 sid = current_sid();
+       int err;
+
+       err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELFROM, NULL);
+       if (err)
+               return err;
+       err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELTO, NULL);
+       if (err)
+               return err;
+
+       sksec->sid = sid;
+
+       return 0;
+}
+
 static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
 {
        int err = 0;
@@ -4353,7 +4457,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        int err;
        char *addrp;
        u32 peer_sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u8 secmark_active;
        u8 netlbl_active;
        u8 peerlbl_active;
@@ -4370,7 +4474,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
                return NF_DROP;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
@@ -4458,7 +4562,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 proto;
 
@@ -4466,7 +4570,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
@@ -4490,7 +4594,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        u32 secmark_perm;
        u32 peer_sid;
        struct sock *sk;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4549,7 +4653,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                secmark_perm = PACKET__SEND;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
@@ -4619,13 +4723,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 static int selinux_netlink_recv(struct sk_buff *skb, int capability)
 {
        int err;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
        err = cap_netlink_recv(skb, capability);
        if (err)
                return err;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.u.cap = capability;
 
        return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
@@ -4684,12 +4788,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = ipc_perms->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = ipc_perms->key;
 
        return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
@@ -4709,7 +4813,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4719,7 +4823,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4739,12 +4843,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq)
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4783,7 +4887,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4804,7 +4908,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        /* Can this process write to the queue? */
@@ -4828,14 +4932,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = task_sid(target);
        int rc;
 
        isec = msq->q_perm.security;
        msec = msg->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid,
@@ -4850,7 +4954,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4860,7 +4964,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4880,12 +4984,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp)
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4942,7 +5046,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4952,7 +5056,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -4972,12 +5076,12 @@ static void selinux_sem_free_security(struct sem_array *sma)
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5195,7 +5299,7 @@ static int selinux_setprocattr(struct task_struct *p,
 
                /* Only allow single threaded processes to change context */
                error = -EPERM;
-               if (!is_single_threaded(p)) {
+               if (!current_is_single_threaded()) {
                        error = security_bounded_transition(tsec->sid, sid);
                        if (error)
                                goto abort_change;
@@ -5252,6 +5356,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
        kfree(secdata);
 }
 
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+}
+
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
+}
+
+static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       int len = 0;
+       len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
+                                               ctx, true);
+       if (len < 0)
+               return len;
+       *ctxlen = len;
+       return 0;
+}
 #ifdef CONFIG_KEYS
 
 static int selinux_key_alloc(struct key *k, const struct cred *cred,
@@ -5323,7 +5453,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 static struct security_operations selinux_ops = {
        .name =                         "selinux",
 
-       .ptrace_may_access =            selinux_ptrace_may_access,
+       .ptrace_access_check =          selinux_ptrace_access_check,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
@@ -5396,10 +5526,13 @@ static struct security_operations selinux_ops = {
        .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
+       .cred_alloc_blank =             selinux_cred_alloc_blank,
        .cred_free =                    selinux_cred_free,
        .cred_prepare =                 selinux_cred_prepare,
+       .cred_transfer =                selinux_cred_transfer,
        .kernel_act_as =                selinux_kernel_act_as,
        .kernel_create_files_as =       selinux_kernel_create_files_as,
+       .kernel_module_request =        selinux_kernel_module_request,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
@@ -5448,6 +5581,9 @@ static struct security_operations selinux_ops = {
        .secid_to_secctx =              selinux_secid_to_secctx,
        .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
+       .inode_notifysecctx =           selinux_inode_notifysecctx,
+       .inode_setsecctx =              selinux_inode_setsecctx,
+       .inode_getsecctx =              selinux_inode_getsecctx,
 
        .unix_stream_connect =          selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
@@ -5477,6 +5613,9 @@ static struct security_operations selinux_ops = {
        .inet_csk_clone =               selinux_inet_csk_clone,
        .inet_conn_established =        selinux_inet_conn_established,
        .req_classify_flow =            selinux_req_classify_flow,
+       .tun_dev_create =               selinux_tun_dev_create,
+       .tun_dev_post_create =          selinux_tun_dev_post_create,
+       .tun_dev_attach =               selinux_tun_dev_attach,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
@@ -5691,6 +5830,9 @@ int selinux_disable(void)
        selinux_disabled = 1;
        selinux_enabled = 0;
 
+       /* Try to destroy the avc node cache */
+       avc_disable();
+
        /* Reset security_ops to the secondary module, dummy or capability. */
        security_ops = secondary_ops;