selinux: Convert isec->lock into a spinlock
authorAndreas Gruenbacher <agruenba@redhat.com>
Tue, 15 Nov 2016 10:06:40 +0000 (11:06 +0100)
committerPaul Moore <paul@paul-moore.com>
Tue, 22 Nov 2016 22:44:02 +0000 (17:44 -0500)
commit9287aed2ad1ff1bde5eb190bcd6dccd5f1cf47d3
tree0d57e7ecdbf0d7c2ac9c377a4a53c5c9b135d38d
parent3322d0d64f4e942862a152f6f11137a1f5eac2e9
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>
security/selinux/hooks.c
security/selinux/include/objsec.h