selinux: Convert isec->lock into a spinlock

Convert isec->lock from a mutex into a spinlock.  Instead of holding
the lock while sleeping in inode_doinit_with_dentry, set
isec->initialized to LABEL_PENDING and release the lock.  Then, when
the sid has been determined, re-acquire the lock.  If isec->initialized
is still set to LABEL_PENDING, set isec->sid; otherwise, the sid has
been set by another task (LABEL_INITIALIZED) or invalidated
(LABEL_INVALID) in the meantime.

This fixes a deadlock on gfs2 where

 * one task is in inode_doinit_with_dentry -> gfs2_getxattr, holds
   isec->lock, and tries to acquire the inode's glock, and

 * another task is in do_xmote -> inode_go_inval ->
   selinux_inode_invalidate_secctx, holds the inode's glock, and
   tries to acquire isec->lock.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
[PM: minor tweaks to keep checkpatch.pl happy]
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Andreas Gruenbacher
2016-11-15 11:06:40 +01:00
committed by Paul Moore
parent 3322d0d64f
commit 9287aed2ad
2 changed files with 66 additions and 40 deletions

View File

@@ -39,7 +39,8 @@ struct task_security_struct {
enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED /* initialized */
LABEL_INITIALIZED, /* initialized */
LABEL_PENDING
};
struct inode_security_struct {
@@ -52,7 +53,7 @@ struct inode_security_struct {
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
unsigned char initialized; /* initialization flag */
struct mutex lock;
spinlock_t lock;
};
struct file_security_struct {