[ Upstream commit 3edeb4a4146dc3b54d6fa71b7ee0585cb52ebfdf ]

When a reconnect happens in the middle of processing a compound chain
the code leaks a buffer from the memory pool. Fix this by properly
checking for a return code and freeing buffers in case of error.

Also maintain a buf variable to be equal to either smallbuf or bigbuf
depending on a response buffer size while parsing a chain and when
returning to the caller.

Signed-off-by: Pavel Shilovsky <pshi...@microsoft.com>
Reviewed-by: Ronnie Sahlberg <lsahl...@redhat.com>
Signed-off-by: Steve French <stfre...@microsoft.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/cifs/smb2ops.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0ccf8f9b63a2e..97fdbec54db97 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -3121,7 +3121,6 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
 {
        int ret, length;
        char *buf = server->smallbuf;
-       char *tmpbuf;
        struct smb2_sync_hdr *shdr;
        unsigned int pdu_length = server->pdu_size;
        unsigned int buf_size;
@@ -3151,18 +3150,15 @@ receive_encrypted_standard(struct TCP_Server_Info 
*server,
                return length;
 
        next_is_large = server->large_buf;
- one_more:
+one_more:
        shdr = (struct smb2_sync_hdr *)buf;
        if (shdr->NextCommand) {
-               if (next_is_large) {
-                       tmpbuf = server->bigbuf;
+               if (next_is_large)
                        next_buffer = (char *)cifs_buf_get();
-               } else {
-                       tmpbuf = server->smallbuf;
+               else
                        next_buffer = (char *)cifs_small_buf_get();
-               }
                memcpy(next_buffer,
-                      tmpbuf + le32_to_cpu(shdr->NextCommand),
+                      buf + le32_to_cpu(shdr->NextCommand),
                       pdu_length - le32_to_cpu(shdr->NextCommand));
        }
 
@@ -3191,12 +3187,21 @@ receive_encrypted_standard(struct TCP_Server_Info 
*server,
                pdu_length -= le32_to_cpu(shdr->NextCommand);
                server->large_buf = next_is_large;
                if (next_is_large)
-                       server->bigbuf = next_buffer;
+                       server->bigbuf = buf = next_buffer;
                else
-                       server->smallbuf = next_buffer;
-
-               buf += le32_to_cpu(shdr->NextCommand);
+                       server->smallbuf = buf = next_buffer;
                goto one_more;
+       } else if (ret != 0) {
+               /*
+                * ret != 0 here means that we didn't get to handle_mid() thus
+                * server->smallbuf and server->bigbuf are still valid. We need
+                * to free next_buffer because it is not going to be used
+                * anywhere.
+                */
+               if (next_is_large)
+                       free_rsp_buf(CIFS_LARGE_BUFFER, next_buffer);
+               else
+                       free_rsp_buf(CIFS_SMALL_BUFFER, next_buffer);
        }
 
        return ret;
-- 
2.20.1



Reply via email to