Commit fab5a1fd authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Greg Kroah-Hartman

SMB3: Fix potential memory leak when processing compound chain

[ Upstream commit 3edeb4a4 ]

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: default avatarPavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 6cb49978
...@@ -3121,7 +3121,6 @@ receive_encrypted_standard(struct TCP_Server_Info *server, ...@@ -3121,7 +3121,6 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
{ {
int ret, length; int ret, length;
char *buf = server->smallbuf; char *buf = server->smallbuf;
char *tmpbuf;
struct smb2_sync_hdr *shdr; struct smb2_sync_hdr *shdr;
unsigned int pdu_length = server->pdu_size; unsigned int pdu_length = server->pdu_size;
unsigned int buf_size; unsigned int buf_size;
...@@ -3151,18 +3150,15 @@ receive_encrypted_standard(struct TCP_Server_Info *server, ...@@ -3151,18 +3150,15 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
return length; return length;
next_is_large = server->large_buf; next_is_large = server->large_buf;
one_more: one_more:
shdr = (struct smb2_sync_hdr *)buf; shdr = (struct smb2_sync_hdr *)buf;
if (shdr->NextCommand) { if (shdr->NextCommand) {
if (next_is_large) { if (next_is_large)
tmpbuf = server->bigbuf;
next_buffer = (char *)cifs_buf_get(); next_buffer = (char *)cifs_buf_get();
} else { else
tmpbuf = server->smallbuf;
next_buffer = (char *)cifs_small_buf_get(); next_buffer = (char *)cifs_small_buf_get();
}
memcpy(next_buffer, memcpy(next_buffer,
tmpbuf + le32_to_cpu(shdr->NextCommand), buf + le32_to_cpu(shdr->NextCommand),
pdu_length - le32_to_cpu(shdr->NextCommand)); pdu_length - le32_to_cpu(shdr->NextCommand));
} }
...@@ -3191,12 +3187,21 @@ receive_encrypted_standard(struct TCP_Server_Info *server, ...@@ -3191,12 +3187,21 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
pdu_length -= le32_to_cpu(shdr->NextCommand); pdu_length -= le32_to_cpu(shdr->NextCommand);
server->large_buf = next_is_large; server->large_buf = next_is_large;
if (next_is_large) if (next_is_large)
server->bigbuf = next_buffer; server->bigbuf = buf = next_buffer;
else else
server->smallbuf = next_buffer; server->smallbuf = buf = next_buffer;
buf += le32_to_cpu(shdr->NextCommand);
goto one_more; 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; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment