cfg80211: fix refcount imbalance when wext is disabled
[safe/jmp/linux-2.6] / security / selinux / hooks.c
index 27b4c55..7a374c2 100644 (file)
@@ -91,7 +91,6 @@
 
 #define NUM_SEL_MNT_OPTS 5
 
-extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 extern struct security_operations *security_ops;
 
@@ -448,6 +447,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);
 
@@ -1531,6 +1534,8 @@ static int inode_has_perm(const struct cred *cred,
        struct common_audit_data ad;
        u32 sid;
 
+       validate_creds(cred);
+
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -2405,7 +2410,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);
 }
 
@@ -2921,6 +2926,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                return rc;
 
        isec->sid = newsid;
+       isec->initialized = 1;
        return 0;
 }
 
@@ -3231,12 +3237,29 @@ static int selinux_task_create(unsigned long clone_flags)
 }
 
 /*
+ * 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);
 }
 
@@ -3260,6 +3283,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
 }
 
 /*
+ * 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
  */
@@ -3303,9 +3337,18 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
        return 0;
 }
 
-static int selinux_kernel_module_request(void)
+static int selinux_kernel_module_request(char *kmod_name)
 {
-       return task_has_system(current, SYSTEM__MODULE_REQUEST);
+       u32 sid;
+       struct common_audit_data ad;
+
+       sid = task_sid(current);
+
+       COMMON_AUDIT_DATA_INIT(&ad, KMOD);
+       ad.u.kmod_name = kmod_name;
+
+       return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
+                           SYSTEM__MODULE_REQUEST, &ad);
 }
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
@@ -4050,7 +4093,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        char *addrp;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
@@ -4112,7 +4155,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                return 0;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.netif = skb->iif;
+       ad.u.net.netif = skb->skb_iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
        if (err)
@@ -4124,7 +4167,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
                if (err)
                        return err;
-               err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
+               err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
                                               peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 0);
@@ -4679,10 +4722,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        if (err)
                return err;
 
-       if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
-               err = selinux_nlmsg_perm(sk, skb);
-
-       return err;
+       return selinux_nlmsg_perm(sk, skb);
 }
 
 static int selinux_netlink_recv(struct sk_buff *skb, int capability)
@@ -5321,6 +5361,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,
@@ -5465,8 +5531,10 @@ 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,
@@ -5518,6 +5586,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,
@@ -5764,12 +5835,12 @@ 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;
 
+       /* Try to destroy the avc node cache */
+       avc_disable();
+
        /* Unregister netfilter hooks. */
        selinux_nf_ip_exit();