| From 7ffbe65578b44fafdef577a360eb0583929f7c6e Mon Sep 17 00:00:00 2001 |
| From: Paulo Alcantara <paulo@paulo.ac> |
| Date: Thu, 5 Jul 2018 13:46:34 -0300 |
| Subject: cifs: Fix infinite loop when using hard mount option |
| |
| From: Paulo Alcantara <paulo@paulo.ac> |
| |
| commit 7ffbe65578b44fafdef577a360eb0583929f7c6e upstream. |
| |
| For every request we send, whether it is SMB1 or SMB2+, we attempt to |
| reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying |
| out the request. |
| |
| So, while server->tcpStatus != CifsNeedReconnect, we wait for the |
| reconnection to succeed on wait_event_interruptible_timeout(). If it |
| returns, that means that either the condition was evaluated to true, or |
| timeout elapsed, or it was interrupted by a signal. |
| |
| Since we're not handling the case where the process woke up due to a |
| received signal (-ERESTARTSYS), the next call to |
| wait_event_interruptible_timeout() will _always_ fail and we end up |
| looping forever inside either cifs_reconnect_tcon() or smb2_reconnect(). |
| |
| Here's an example of how to trigger that: |
| |
| $ mount.cifs //foo/share /mnt/test -o |
| username=foo,password=foo,vers=1.0,hard |
| |
| (break connection to server before executing bellow cmd) |
| $ stat -f /mnt/test & sleep 140 |
| [1] 2511 |
| |
| $ ps -aux -q 2511 |
| USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND |
| root 2511 0.0 0.0 12892 1008 pts/0 S 12:24 0:00 stat -f |
| /mnt/test |
| |
| $ kill -9 2511 |
| |
| (wait for a while; process is stuck in the kernel) |
| $ ps -aux -q 2511 |
| USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND |
| root 2511 83.2 0.0 12892 1008 pts/0 R 12:24 30:01 stat -f |
| /mnt/test |
| |
| By using 'hard' mount point means that cifs.ko will keep retrying |
| indefinitely, however we must allow the process to be killed otherwise |
| it would hang the system. |
| |
| Signed-off-by: Paulo Alcantara <palcantara@suse.de> |
| Cc: stable@vger.kernel.org |
| Reviewed-by: Aurelien Aptel <aaptel@suse.com> |
| Signed-off-by: Steve French <stfrench@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/cifs/cifssmb.c | 10 ++++++++-- |
| fs/cifs/smb2pdu.c | 18 ++++++++++++------ |
| 2 files changed, 20 insertions(+), 8 deletions(-) |
| |
| --- a/fs/cifs/cifssmb.c |
| +++ b/fs/cifs/cifssmb.c |
| @@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tc |
| * greater than cifs socket timeout which is 7 seconds |
| */ |
| while (server->tcpStatus == CifsNeedReconnect) { |
| - wait_event_interruptible_timeout(server->response_q, |
| - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
| + rc = wait_event_interruptible_timeout(server->response_q, |
| + (server->tcpStatus != CifsNeedReconnect), |
| + 10 * HZ); |
| + if (rc < 0) { |
| + cifs_dbg(FYI, "%s: aborting reconnect due to a received" |
| + " signal by the process\n", __func__); |
| + return -ERESTARTSYS; |
| + } |
| |
| /* are we still trying to reconnect? */ |
| if (server->tcpStatus != CifsNeedReconnect) |
| --- a/fs/cifs/smb2pdu.c |
| +++ b/fs/cifs/smb2pdu.c |
| @@ -158,7 +158,7 @@ out: |
| static int |
| smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) |
| { |
| - int rc = 0; |
| + int rc; |
| struct nls_table *nls_codepage; |
| struct cifs_ses *ses; |
| struct TCP_Server_Info *server; |
| @@ -169,10 +169,10 @@ smb2_reconnect(__le16 smb2_command, stru |
| * for those three - in the calling routine. |
| */ |
| if (tcon == NULL) |
| - return rc; |
| + return 0; |
| |
| if (smb2_command == SMB2_TREE_CONNECT) |
| - return rc; |
| + return 0; |
| |
| if (tcon->tidStatus == CifsExiting) { |
| /* |
| @@ -215,8 +215,14 @@ smb2_reconnect(__le16 smb2_command, stru |
| return -EAGAIN; |
| } |
| |
| - wait_event_interruptible_timeout(server->response_q, |
| - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
| + rc = wait_event_interruptible_timeout(server->response_q, |
| + (server->tcpStatus != CifsNeedReconnect), |
| + 10 * HZ); |
| + if (rc < 0) { |
| + cifs_dbg(FYI, "%s: aborting reconnect due to a received" |
| + " signal by the process\n", __func__); |
| + return -ERESTARTSYS; |
| + } |
| |
| /* are we still trying to reconnect? */ |
| if (server->tcpStatus != CifsNeedReconnect) |
| @@ -234,7 +240,7 @@ smb2_reconnect(__le16 smb2_command, stru |
| } |
| |
| if (!tcon->ses->need_reconnect && !tcon->need_reconnect) |
| - return rc; |
| + return 0; |
| |
| nls_codepage = load_nls_default(); |
| |