| From 07ccfa42f5c508db49d8d2d94adb563859375fbe Mon Sep 17 00:00:00 2001 |
| From: Paul Moore <pmoore@redhat.com> |
| Date: Mon, 25 Mar 2013 03:18:33 +0000 |
| Subject: [PATCH] unix: fix a race condition in unix_release() |
| |
| commit ded34e0fe8fe8c2d595bfa30626654e4b87621e0 upstream. |
| |
| As reported by Jan, and others over the past few years, there is a |
| race condition caused by unix_release setting the sock->sk pointer |
| to NULL before properly marking the socket as dead/orphaned. This |
| can cause a problem with the LSM hook security_unix_may_send() if |
| there is another socket attempting to write to this partially |
| released socket in between when sock->sk is set to NULL and it is |
| marked as dead/orphaned. This patch fixes this by only setting |
| sock->sk to NULL after the socket has been marked as dead; I also |
| take the opportunity to make unix_release_sock() a void function |
| as it only ever returned 0/success. |
| |
| Dave, I think this one should go on the -stable pile. |
| |
| Special thanks to Jan for coming up with a reproducer for this |
| problem. |
| |
| Reported-by: Jan Stancek <jan.stancek@gmail.com> |
| Signed-off-by: Paul Moore <pmoore@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| net/unix/af_unix.c | 7 +++---- |
| 1 file changed, 3 insertions(+), 4 deletions(-) |
| |
| diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c |
| index 0b7148bed6b3..072835bc61fa 100644 |
| --- a/net/unix/af_unix.c |
| +++ b/net/unix/af_unix.c |
| @@ -370,7 +370,7 @@ static void unix_sock_destructor(struct sock *sk) |
| #endif |
| } |
| |
| -static int unix_release_sock(struct sock *sk, int embrion) |
| +static void unix_release_sock(struct sock *sk, int embrion) |
| { |
| struct unix_sock *u = unix_sk(sk); |
| struct dentry *dentry; |
| @@ -445,8 +445,6 @@ static int unix_release_sock(struct sock *sk, int embrion) |
| |
| if (unix_tot_inflight) |
| unix_gc(); /* Garbage collect fds */ |
| - |
| - return 0; |
| } |
| |
| static int unix_listen(struct socket *sock, int backlog) |
| @@ -661,9 +659,10 @@ static int unix_release(struct socket *sock) |
| if (!sk) |
| return 0; |
| |
| + unix_release_sock(sk, 0); |
| sock->sk = NULL; |
| |
| - return unix_release_sock(sk, 0); |
| + return 0; |
| } |
| |
| static int unix_autobind(struct socket *sock) |
| -- |
| 1.8.5.2 |
| |