Skip to content

Commit

Permalink
selinux: fix inode security list corruption
Browse files Browse the repository at this point in the history
commit 923190d32de4428afbea5e5773be86bea60a9925 upstream.

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.

Change-Id: Iac9264851e98933deabedaa9c4ead434669a07a8
Reported-by: Shivnandan Kumar <[email protected]>
Signed-off-by: Stephen Smalley <[email protected]>
Signed-off-by: Paul Moore <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
stephensmalley authored and Christopher83 committed Feb 2, 2015
1 parent 94ea5c5 commit b3634c0
Showing 1 changed file with 1 addition and 1 deletion.
2 changes: 1 addition & 1 deletion security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ static int sb_finish_set_opts(struct super_block *sb)
list_entry(sbsec->isec_head.next,
struct inode_security_struct, list);
struct inode *inode = isec->inode;
list_del_init(&isec->list);
spin_unlock(&sbsec->isec_lock);
inode = igrab(inode);
if (inode) {
Expand All @@ -447,7 +448,6 @@ static int sb_finish_set_opts(struct super_block *sb)
iput(inode);
}
spin_lock(&sbsec->isec_lock);
list_del_init(&isec->list);
goto next_inode;
}
spin_unlock(&sbsec->isec_lock);
Expand Down

0 comments on commit b3634c0

Please sign in to comment.