aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2014-10-06 16:32:52 -0400
committerPaul Moore <pmoore@redhat.com>2014-10-15 10:37:02 -0400
commit923190d32de4428afbea5e5773be86bea60a9925 (patch)
tree77cf1c0fad3b89b66b637d453125616ba5ed55d3 /security
parent4093a8443941d7021c7f747474a87a56cf666270 (diff)
selinux: fix inode security list corruption
sb_finish_set_opts() can race with inode_free_security() when initializing inode security structures for inodes created prior to initial policy load or by the filesystem during ->mount(). This appears to have always been a possible race, but commit 3dc91d4 ("SELinux: Fix possible NULL pointer dereference in selinux_inode_permission()") made it more evident by immediately reusing the unioned list/rcu element of the inode security structure for call_rcu() upon an inode_free_security(). But the underlying issue was already present before that commit as a possible use-after-free of isec. Shivnandan Kumar reported the list corruption and proposed a patch to split the list and rcu elements out of the union as separate fields of the inode_security_struct so that setting the rcu element would not affect the list element. However, this would merely hide the issue and not truly fix the code. This patch instead moves up the deletion of the list entry prior to dropping the sbsec->isec_lock initially. Then, if the inode is dropped subsequently, there will be no further references to the isec. Reported-by: Shivnandan Kumar <shivnandan.k@samsung.com> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Cc: stable@vger.kernel.org Signed-off-by: Paul Moore <pmoore@redhat.com>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/hooks.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 29e64d4ca099..2478976fc894 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -481,6 +481,7 @@ next_inode:
481 list_entry(sbsec->isec_head.next, 481 list_entry(sbsec->isec_head.next,
482 struct inode_security_struct, list); 482 struct inode_security_struct, list);
483 struct inode *inode = isec->inode; 483 struct inode *inode = isec->inode;
484 list_del_init(&isec->list);
484 spin_unlock(&sbsec->isec_lock); 485 spin_unlock(&sbsec->isec_lock);
485 inode = igrab(inode); 486 inode = igrab(inode);
486 if (inode) { 487 if (inode) {
@@ -489,7 +490,6 @@ next_inode:
489 iput(inode); 490 iput(inode);
490 } 491 }
491 spin_lock(&sbsec->isec_lock); 492 spin_lock(&sbsec->isec_lock);
492 list_del_init(&isec->list);
493 goto next_inode; 493 goto next_inode;
494 } 494 }
495 spin_unlock(&sbsec->isec_lock); 495 spin_unlock(&sbsec->isec_lock);