]> Git Repo - linux.git/blobdiff - security/selinux/hooks.c
drm/i915/dsi: Skip delays for v3 VBTs in vid-mode
[linux.git] / security / selinux / hooks.c
index 38b79d797aaf8c3f5abebe6578ab5c6cf91f6a9c..d98550abe16d40250be4327197c48866953b5645 100644 (file)
@@ -231,12 +231,13 @@ static int inode_alloc_security(struct inode *inode)
        if (!isec)
                return -ENOMEM;
 
-       mutex_init(&isec->lock);
+       spin_lock_init(&isec->lock);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
        isec->sid = SECINITSID_UNLABELED;
        isec->sclass = SECCLASS_FILE;
        isec->task_sid = sid;
+       isec->initialized = LABEL_INVALID;
        inode->i_security = isec;
 
        return 0;
@@ -247,7 +248,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 /*
  * Try reloading inode security labels that have been marked as invalid.  The
  * @may_sleep parameter indicates when sleeping and thus reloading labels is
- * allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is
+ * allowed; when set to false, returns -ECHILD when the label is
  * invalid.  The @opt_dentry parameter should be set to a dentry of the inode;
  * when no dentry is available, set it to NULL instead.
  */
@@ -1100,11 +1101,12 @@ static int selinux_parse_opts_str(char *options,
        }
 
        rc = -ENOMEM;
-       opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
+       opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL);
        if (!opts->mnt_opts)
                goto out_err;
 
-       opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
+       opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int),
+                                      GFP_KERNEL);
        if (!opts->mnt_opts_flags) {
                kfree(opts->mnt_opts);
                goto out_err;
@@ -1380,7 +1382,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 {
        struct superblock_security_struct *sbsec = NULL;
        struct inode_security_struct *isec = inode->i_security;
-       u32 sid;
+       u32 task_sid, sid = 0;
+       u16 sclass;
        struct dentry *dentry;
 #define INITCONTEXTLEN 255
        char *context = NULL;
@@ -1388,12 +1391,15 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
        int rc = 0;
 
        if (isec->initialized == LABEL_INITIALIZED)
-               goto out;
+               return 0;
 
-       mutex_lock(&isec->lock);
+       spin_lock(&isec->lock);
        if (isec->initialized == LABEL_INITIALIZED)
                goto out_unlock;
 
+       if (isec->sclass == SECCLASS_FILE)
+               isec->sclass = inode_mode_to_security_class(inode->i_mode);
+
        sbsec = inode->i_sb->s_security;
        if (!(sbsec->flags & SE_SBINITIALIZED)) {
                /* Defer initialization until selinux_complete_init,
@@ -1406,12 +1412,18 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                goto out_unlock;
        }
 
+       sclass = isec->sclass;
+       task_sid = isec->task_sid;
+       sid = isec->sid;
+       isec->initialized = LABEL_PENDING;
+       spin_unlock(&isec->lock);
+
        switch (sbsec->behavior) {
        case SECURITY_FS_USE_NATIVE:
                break;
        case SECURITY_FS_USE_XATTR:
                if (!(inode->i_opflags & IOP_XATTR)) {
-                       isec->sid = sbsec->def_sid;
+                       sid = sbsec->def_sid;
                        break;
                }
                /* Need a dentry, since the xattr API requires one.
@@ -1433,7 +1445,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                         * inode_doinit with a dentry, before these inodes could
                         * be used again by userspace.
                         */
-                       goto out_unlock;
+                       goto out;
                }
 
                len = INITCONTEXTLEN;
@@ -1441,7 +1453,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                if (!context) {
                        rc = -ENOMEM;
                        dput(dentry);
-                       goto out_unlock;
+                       goto out;
                }
                context[len] = '\0';
                rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
@@ -1452,14 +1464,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
                        if (rc < 0) {
                                dput(dentry);
-                               goto out_unlock;
+                               goto out;
                        }
                        len = rc;
                        context = kmalloc(len+1, GFP_NOFS);
                        if (!context) {
                                rc = -ENOMEM;
                                dput(dentry);
-                               goto out_unlock;
+                               goto out;
                        }
                        context[len] = '\0';
                        rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
@@ -1471,7 +1483,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                                       "%d for dev=%s ino=%ld\n", __func__,
                                       -rc, inode->i_sb->s_id, inode->i_ino);
                                kfree(context);
-                               goto out_unlock;
+                               goto out;
                        }
                        /* Map ENODATA to the default file SID */
                        sid = sbsec->def_sid;
@@ -1501,29 +1513,25 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                        }
                }
                kfree(context);
-               isec->sid = sid;
                break;
        case SECURITY_FS_USE_TASK:
-               isec->sid = isec->task_sid;
+               sid = task_sid;
                break;
        case SECURITY_FS_USE_TRANS:
                /* Default to the fs SID. */
-               isec->sid = sbsec->sid;
+               sid = sbsec->sid;
 
                /* 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, NULL, &sid);
+               rc = security_transition_sid(task_sid, sid, sclass, NULL, &sid);
                if (rc)
-                       goto out_unlock;
-               isec->sid = sid;
+                       goto out;
                break;
        case SECURITY_FS_USE_MNTPOINT:
-               isec->sid = sbsec->mntpoint_sid;
+               sid = sbsec->mntpoint_sid;
                break;
        default:
                /* Default to the fs superblock SID. */
-               isec->sid = sbsec->sid;
+               sid = sbsec->sid;
 
                if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
                        /* We must have a dentry to determine the label on
@@ -1546,25 +1554,30 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                         * could be used again by userspace.
                         */
                        if (!dentry)
-                               goto out_unlock;
-                       isec->sclass = inode_mode_to_security_class(inode->i_mode);
-                       rc = selinux_genfs_get_sid(dentry, isec->sclass,
+                               goto out;
+                       rc = selinux_genfs_get_sid(dentry, sclass,
                                                   sbsec->flags, &sid);
                        dput(dentry);
                        if (rc)
-                               goto out_unlock;
-                       isec->sid = sid;
+                               goto out;
                }
                break;
        }
 
-       isec->initialized = LABEL_INITIALIZED;
+out:
+       spin_lock(&isec->lock);
+       if (isec->initialized == LABEL_PENDING) {
+               if (!sid || rc) {
+                       isec->initialized = LABEL_INVALID;
+                       goto out_unlock;
+               }
+
+               isec->initialized = LABEL_INITIALIZED;
+               isec->sid = sid;
+       }
 
 out_unlock:
-       mutex_unlock(&isec->lock);
-out:
-       if (isec->sclass == SECCLASS_FILE)
-               isec->sclass = inode_mode_to_security_class(inode->i_mode);
+       spin_unlock(&isec->lock);
        return rc;
 }
 
@@ -3198,9 +3211,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
        }
 
        isec = backing_inode_security(dentry);
+       spin_lock(&isec->lock);
        isec->sclass = inode_mode_to_security_class(inode->i_mode);
        isec->sid = newsid;
        isec->initialized = LABEL_INITIALIZED;
+       spin_unlock(&isec->lock);
 
        return;
 }
@@ -3293,9 +3308,11 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (rc)
                return rc;
 
+       spin_lock(&isec->lock);
        isec->sclass = inode_mode_to_security_class(inode->i_mode);
        isec->sid = newsid;
        isec->initialized = LABEL_INITIALIZED;
+       spin_unlock(&isec->lock);
        return 0;
 }
 
@@ -3956,8 +3973,11 @@ static void selinux_task_to_inode(struct task_struct *p,
        struct inode_security_struct *isec = inode->i_security;
        u32 sid = task_sid(p);
 
+       spin_lock(&isec->lock);
+       isec->sclass = inode_mode_to_security_class(inode->i_mode);
        isec->sid = sid;
        isec->initialized = LABEL_INITIALIZED;
+       spin_unlock(&isec->lock);
 }
 
 /* Returns error only if unable to parse addresses */
@@ -4276,24 +4296,24 @@ static int selinux_socket_post_create(struct socket *sock, int family,
        const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
        struct sk_security_struct *sksec;
+       u16 sclass = socket_type_to_security_class(family, type, protocol);
+       u32 sid = SECINITSID_KERNEL;
        int err = 0;
 
-       isec->sclass = socket_type_to_security_class(family, type, protocol);
-
-       if (kern)
-               isec->sid = SECINITSID_KERNEL;
-       else {
-               err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid));
+       if (!kern) {
+               err = socket_sockcreate_sid(tsec, sclass, &sid);
                if (err)
                        return err;
        }
 
+       isec->sclass = sclass;
+       isec->sid = sid;
        isec->initialized = LABEL_INITIALIZED;
 
        if (sock->sk) {
                sksec = sock->sk->sk_security;
-               sksec->sid = isec->sid;
-               sksec->sclass = isec->sclass;
+               sksec->sclass = sclass;
+               sksec->sid = sid;
                err = selinux_netlbl_socket_post_create(sock->sk, family);
        }
 
@@ -4469,16 +4489,22 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        int err;
        struct inode_security_struct *isec;
        struct inode_security_struct *newisec;
+       u16 sclass;
+       u32 sid;
 
        err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
 
-       newisec = inode_security_novalidate(SOCK_INODE(newsock));
-
        isec = inode_security_novalidate(SOCK_INODE(sock));
-       newisec->sclass = isec->sclass;
-       newisec->sid = isec->sid;
+       spin_lock(&isec->lock);
+       sclass = isec->sclass;
+       sid = isec->sid;
+       spin_unlock(&isec->lock);
+
+       newisec = inode_security_novalidate(SOCK_INODE(newsock));
+       newisec->sclass = sclass;
+       newisec->sid = sid;
        newisec->initialized = LABEL_INITIALIZED;
 
        return 0;
@@ -5861,7 +5887,7 @@ static int selinux_setprocattr(struct task_struct *p,
                return error;
 
        /* Obtain a SID for the context, if one was specified. */
-       if (size && str[1] && str[1] != '\n') {
+       if (size && str[0] && str[0] != '\n') {
                if (str[size-1] == '\n') {
                        str[size-1] = 0;
                        size--;
@@ -5981,9 +6007,9 @@ static void selinux_inode_invalidate_secctx(struct inode *inode)
 {
        struct inode_security_struct *isec = inode->i_security;
 
-       mutex_lock(&isec->lock);
+       spin_lock(&isec->lock);
        isec->initialized = LABEL_INVALID;
-       mutex_unlock(&isec->lock);
+       spin_unlock(&isec->lock);
 }
 
 /*
This page took 0.040589 seconds and 4 git commands to generate.