Skip to content

Commit f4876d4

Browse files
rohiths-msftksacilotto
authored andcommitted
smb3: Avoid Mid pending list corruption
BugLink: https://bugs.launchpad.net/bugs/1908562 commit ac873aa upstream. When reconnect happens Mid queue can be corrupted when both demultiplex and offload thread try to dequeue the MID from the pending list. These patches address a problem found during decryption offload: CIFS: VFS: trying to dequeue a deleted mid that could cause a refcount use after free: Workqueue: smb3decryptd smb2_decrypt_offload [cifs] Signed-off-by: Rohith Surabattula <[email protected]> Reviewed-by: Pavel Shilovsky <[email protected]> CC: Stable <[email protected]> #5.4+ Signed-off-by: Steve French <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Ian May <[email protected]>
1 parent 1f0c621 commit f4876d4

File tree

1 file changed

+46
-9
lines changed

1 file changed

+46
-9
lines changed

fs/cifs/smb2ops.c

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
259259
}
260260

261261
static struct mid_q_entry *
262-
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
262+
__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
263263
{
264264
struct mid_q_entry *mid;
265265
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
@@ -276,6 +276,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
276276
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
277277
(mid->command == shdr->Command)) {
278278
kref_get(&mid->refcount);
279+
if (dequeue) {
280+
list_del_init(&mid->qhead);
281+
mid->mid_flags |= MID_DELETED;
282+
}
279283
spin_unlock(&GlobalMid_Lock);
280284
return mid;
281285
}
@@ -284,6 +288,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
284288
return NULL;
285289
}
286290

291+
static struct mid_q_entry *
292+
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
293+
{
294+
return __smb2_find_mid(server, buf, false);
295+
}
296+
297+
static struct mid_q_entry *
298+
smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
299+
{
300+
return __smb2_find_mid(server, buf, true);
301+
}
302+
287303
static void
288304
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
289305
{
@@ -4067,7 +4083,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
40674083
cifs_dbg(FYI, "%s: server returned error %d\n",
40684084
__func__, rdata->result);
40694085
/* normal error on read response */
4070-
dequeue_mid(mid, false);
4086+
if (is_offloaded)
4087+
mid->mid_state = MID_RESPONSE_RECEIVED;
4088+
else
4089+
dequeue_mid(mid, false);
40714090
return 0;
40724091
}
40734092

@@ -4091,7 +4110,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
40914110
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
40924111
__func__, data_offset);
40934112
rdata->result = -EIO;
4094-
dequeue_mid(mid, rdata->result);
4113+
if (is_offloaded)
4114+
mid->mid_state = MID_RESPONSE_MALFORMED;
4115+
else
4116+
dequeue_mid(mid, rdata->result);
40954117
return 0;
40964118
}
40974119

@@ -4107,21 +4129,30 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
41074129
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
41084130
__func__, data_offset);
41094131
rdata->result = -EIO;
4110-
dequeue_mid(mid, rdata->result);
4132+
if (is_offloaded)
4133+
mid->mid_state = MID_RESPONSE_MALFORMED;
4134+
else
4135+
dequeue_mid(mid, rdata->result);
41114136
return 0;
41124137
}
41134138

41144139
if (data_len > page_data_size - pad_len) {
41154140
/* data_len is corrupt -- discard frame */
41164141
rdata->result = -EIO;
4117-
dequeue_mid(mid, rdata->result);
4142+
if (is_offloaded)
4143+
mid->mid_state = MID_RESPONSE_MALFORMED;
4144+
else
4145+
dequeue_mid(mid, rdata->result);
41184146
return 0;
41194147
}
41204148

41214149
rdata->result = init_read_bvec(pages, npages, page_data_size,
41224150
cur_off, &bvec);
41234151
if (rdata->result != 0) {
4124-
dequeue_mid(mid, rdata->result);
4152+
if (is_offloaded)
4153+
mid->mid_state = MID_RESPONSE_MALFORMED;
4154+
else
4155+
dequeue_mid(mid, rdata->result);
41254156
return 0;
41264157
}
41274158

@@ -4136,7 +4167,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
41364167
/* read response payload cannot be in both buf and pages */
41374168
WARN_ONCE(1, "buf can not contain only a part of read data");
41384169
rdata->result = -EIO;
4139-
dequeue_mid(mid, rdata->result);
4170+
if (is_offloaded)
4171+
mid->mid_state = MID_RESPONSE_MALFORMED;
4172+
else
4173+
dequeue_mid(mid, rdata->result);
41404174
return 0;
41414175
}
41424176

@@ -4147,7 +4181,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
41474181
if (length < 0)
41484182
return length;
41494183

4150-
dequeue_mid(mid, false);
4184+
if (is_offloaded)
4185+
mid->mid_state = MID_RESPONSE_RECEIVED;
4186+
else
4187+
dequeue_mid(mid, false);
41514188
return length;
41524189
}
41534190

@@ -4176,7 +4213,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
41764213
}
41774214

41784215
dw->server->lstrp = jiffies;
4179-
mid = smb2_find_mid(dw->server, dw->buf);
4216+
mid = smb2_find_dequeue_mid(dw->server, dw->buf);
41804217
if (mid == NULL)
41814218
cifs_dbg(FYI, "mid not found\n");
41824219
else {

0 commit comments

Comments
 (0)