Merge tag 'selinux-pr-20180629' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 30 Jun 2018 18:15:12 +0000 (11:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 30 Jun 2018 18:15:12 +0000 (11:15 -0700)
Pull selinux fix from Paul Moore:
 "One fairly straightforward patch to fix a longstanding issue where a
  process could stall while accessing files in selinuxfs and block
  everyone else due to a held mutex.

  The patch passes all our tests and looks to apply cleanly to your
  current tree"

* tag 'selinux-pr-20180629' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: move user accesses in selinuxfs out of locked regions

1  2 
security/selinux/selinuxfs.c

index f3d374d2ca045ce7325b20ad3cecb6304418d1b3,19e35dd695d7a4efda74b270a00ceb1e074ab7cc..79d3709b06717a1f6452fe85b9922244b9f70381
@@@ -167,7 -167,7 +167,7 @@@ static ssize_t sel_write_enforce(struc
                                      NULL);
                if (length)
                        goto out;
 -              audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
 +              audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
                        "enforcing=%d old_enforcing=%d auid=%u ses=%u"
                        " enabled=%d old-enabled=%d lsm=selinux res=1",
                        new_value, old_value,
@@@ -303,7 -303,7 +303,7 @@@ static ssize_t sel_write_disable(struc
                length = selinux_disable(fsi->state);
                if (length)
                        goto out;
 -              audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
 +              audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
                        "enforcing=%d old_enforcing=%d auid=%u ses=%u"
                        " enabled=%d old-enabled=%d lsm=selinux res=1",
                        enforcing, enforcing,
@@@ -441,22 -441,16 +441,16 @@@ static int sel_release_policy(struct in
  static ssize_t sel_read_policy(struct file *filp, char __user *buf,
                               size_t count, loff_t *ppos)
  {
-       struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
        struct policy_load_memory *plm = filp->private_data;
        int ret;
  
-       mutex_lock(&fsi->mutex);
        ret = avc_has_perm(&selinux_state,
                           current_sid(), SECINITSID_SECURITY,
                          SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
        if (ret)
-               goto out;
+               return ret;
  
-       ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
- out:
-       mutex_unlock(&fsi->mutex);
-       return ret;
+       return simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
  }
  
  static vm_fault_t sel_mmap_policy_fault(struct vm_fault *vmf)
@@@ -581,7 -575,7 +575,7 @@@ static ssize_t sel_write_load(struct fi
        length = count;
  
  out1:
 -      audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
 +      audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
                "auid=%u ses=%u lsm=selinux res=1",
                from_kuid(&init_user_ns, audit_get_loginuid(current)),
                audit_get_sessionid(current));
@@@ -1188,25 -1182,29 +1182,29 @@@ static ssize_t sel_read_bool(struct fil
        ret = -EINVAL;
        if (index >= fsi->bool_num || strcmp(name,
                                             fsi->bool_pending_names[index]))
-               goto out;
+               goto out_unlock;
  
        ret = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               goto out;
+               goto out_unlock;
  
        cur_enforcing = security_get_bool_value(fsi->state, index);
        if (cur_enforcing < 0) {
                ret = cur_enforcing;
-               goto out;
+               goto out_unlock;
        }
        length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
                          fsi->bool_pending_values[index]);
-       ret = simple_read_from_buffer(buf, count, ppos, page, length);
- out:
        mutex_unlock(&fsi->mutex);
+       ret = simple_read_from_buffer(buf, count, ppos, page, length);
+ out_free:
        free_page((unsigned long)page);
        return ret;
+ out_unlock:
+       mutex_unlock(&fsi->mutex);
+       goto out_free;
  }
  
  static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
        const char *name = filep->f_path.dentry->d_name.name;
  
+       if (count >= PAGE_SIZE)
+               return -ENOMEM;
+       /* No partial writes. */
+       if (*ppos != 0)
+               return -EINVAL;
+       page = memdup_user_nul(buf, count);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
        mutex_lock(&fsi->mutex);
  
        length = avc_has_perm(&selinux_state,
                                             fsi->bool_pending_names[index]))
                goto out;
  
-       length = -ENOMEM;
-       if (count >= PAGE_SIZE)
-               goto out;
-       /* No partial writes. */
-       length = -EINVAL;
-       if (*ppos != 0)
-               goto out;
-       page = memdup_user_nul(buf, count);
-       if (IS_ERR(page)) {
-               length = PTR_ERR(page);
-               page = NULL;
-               goto out;
-       }
        length = -EINVAL;
        if (sscanf(page, "%d", &new_value) != 1)
                goto out;
@@@ -1280,6 -1273,17 +1273,17 @@@ static ssize_t sel_commit_bools_write(s
        ssize_t length;
        int new_value;
  
+       if (count >= PAGE_SIZE)
+               return -ENOMEM;
+       /* No partial writes. */
+       if (*ppos != 0)
+               return -EINVAL;
+       page = memdup_user_nul(buf, count);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
        mutex_lock(&fsi->mutex);
  
        length = avc_has_perm(&selinux_state,
        if (length)
                goto out;
  
-       length = -ENOMEM;
-       if (count >= PAGE_SIZE)
-               goto out;
-       /* No partial writes. */
-       length = -EINVAL;
-       if (*ppos != 0)
-               goto out;
-       page = memdup_user_nul(buf, count);
-       if (IS_ERR(page)) {
-               length = PTR_ERR(page);
-               page = NULL;
-               goto out;
-       }
        length = -EINVAL;
        if (sscanf(page, "%d", &new_value) != 1)
                goto out;