diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-01-13 14:44:41 +0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-01-13 14:44:41 +0400 |
commit | 1c62448e39285b23b4770aaf46d32368fff990df (patch) | |
tree | c6c6cf1a80a762a5859bfdaf3941294a47ea8eee /security/selinux/hooks.c | |
parent | 47933ad41a86a4a9b50bed7c9b9bd2ba242aac63 (diff) | |
parent | 7e22e91102c6b9df7c4ae2168910e19d2bb14cd6 (diff) | |
download | linux-1c62448e39285b23b4770aaf46d32368fff990df.tar.xz |
Merge tag 'v3.13-rc8' into core/locking
Refresh the tree with the latest fixes, before applying new changes.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 28 |
1 files changed, 23 insertions, 5 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 419491d8e7d2..57b0b49f4e6e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -234,6 +234,14 @@ static int inode_alloc_security(struct inode *inode) return 0; } +static void inode_free_rcu(struct rcu_head *head) +{ + struct inode_security_struct *isec; + + isec = container_of(head, struct inode_security_struct, rcu); + kmem_cache_free(sel_inode_cache, isec); +} + static void inode_free_security(struct inode *inode) { struct inode_security_struct *isec = inode->i_security; @@ -244,8 +252,16 @@ static void inode_free_security(struct inode *inode) list_del_init(&isec->list); spin_unlock(&sbsec->isec_lock); - inode->i_security = NULL; - kmem_cache_free(sel_inode_cache, isec); + /* + * The inode may still be referenced in a path walk and + * a call to selinux_inode_permission() can be made + * after inode_free_security() is called. Ideally, the VFS + * wouldn't do this, but fixing that is a much harder + * job. For now, simply free the i_security via RCU, and + * leave the current inode->i_security pointer intact. + * The inode will be freed after the RCU grace period too. + */ + call_rcu(&isec->rcu, inode_free_rcu); } static int file_alloc_security(struct file *file) @@ -4334,8 +4350,10 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) } err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); - if (err) + if (err) { selinux_netlbl_err(skb, err, 0); + return err; + } } if (secmark_active) { @@ -5586,11 +5604,11 @@ static int selinux_setprocattr(struct task_struct *p, /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ ptsid = 0; - task_lock(p); + rcu_read_lock(); tracer = ptrace_parent(p); if (tracer) ptsid = task_sid(tracer); - task_unlock(p); + rcu_read_unlock(); if (tracer) { error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, |