aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilov@microsoft.com>2019-07-22 14:38:22 -0400
committerSteve French <stfrench@microsoft.com>2019-08-05 23:50:13 -0400
commit3edeb4a4146dc3b54d6fa71b7ee0585cb52ebfdf (patch)
tree6c4487f7274644d38f128e31e37bba38f9880085 /fs/cifs
parente99c63e4d86d3a94818693147b469fa70de6f945 (diff)
SMB3: Fix potential memory leak when processing compound chain
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 <pshilov@microsoft.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/smb2ops.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index a5bc1b671c12..19589922ef2b 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -4070,7 +4070,6 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
4070{ 4070{
4071 int ret, length; 4071 int ret, length;
4072 char *buf = server->smallbuf; 4072 char *buf = server->smallbuf;
4073 char *tmpbuf;
4074 struct smb2_sync_hdr *shdr; 4073 struct smb2_sync_hdr *shdr;
4075 unsigned int pdu_length = server->pdu_size; 4074 unsigned int pdu_length = server->pdu_size;
4076 unsigned int buf_size; 4075 unsigned int buf_size;
@@ -4100,18 +4099,15 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
4100 return length; 4099 return length;
4101 4100
4102 next_is_large = server->large_buf; 4101 next_is_large = server->large_buf;
4103 one_more: 4102one_more:
4104 shdr = (struct smb2_sync_hdr *)buf; 4103 shdr = (struct smb2_sync_hdr *)buf;
4105 if (shdr->NextCommand) { 4104 if (shdr->NextCommand) {
4106 if (next_is_large) { 4105 if (next_is_large)
4107 tmpbuf = server->bigbuf;
4108 next_buffer = (char *)cifs_buf_get(); 4106 next_buffer = (char *)cifs_buf_get();
4109 } else { 4107 else
4110 tmpbuf = server->smallbuf;
4111 next_buffer = (char *)cifs_small_buf_get(); 4108 next_buffer = (char *)cifs_small_buf_get();
4112 }
4113 memcpy(next_buffer, 4109 memcpy(next_buffer,
4114 tmpbuf + le32_to_cpu(shdr->NextCommand), 4110 buf + le32_to_cpu(shdr->NextCommand),
4115 pdu_length - le32_to_cpu(shdr->NextCommand)); 4111 pdu_length - le32_to_cpu(shdr->NextCommand));
4116 } 4112 }
4117 4113
@@ -4140,12 +4136,21 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
4140 pdu_length -= le32_to_cpu(shdr->NextCommand); 4136 pdu_length -= le32_to_cpu(shdr->NextCommand);
4141 server->large_buf = next_is_large; 4137 server->large_buf = next_is_large;
4142 if (next_is_large) 4138 if (next_is_large)
4143 server->bigbuf = next_buffer; 4139 server->bigbuf = buf = next_buffer;
4144 else 4140 else
4145 server->smallbuf = next_buffer; 4141 server->smallbuf = buf = next_buffer;
4146
4147 buf += le32_to_cpu(shdr->NextCommand);
4148 goto one_more; 4142 goto one_more;
4143 } else if (ret != 0) {
4144 /*
4145 * ret != 0 here means that we didn't get to handle_mid() thus
4146 * server->smallbuf and server->bigbuf are still valid. We need
4147 * to free next_buffer because it is not going to be used
4148 * anywhere.
4149 */
4150 if (next_is_large)
4151 free_rsp_buf(CIFS_LARGE_BUFFER, next_buffer);
4152 else
4153 free_rsp_buf(CIFS_SMALL_BUFFER, next_buffer);
4149 } 4154 }
4150 4155
4151 return ret; 4156 return ret;