Skip to content

Commit ac873aa

Browse files
rohiths-msftSteve French
authored and
Steve French
committed
smb3: Avoid Mid pending list corruption
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]>
1 parent de9ac0a commit ac873aa

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
@@ -264,7 +264,7 @@ smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
264264
}
265265

266266
static struct mid_q_entry *
267-
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
267+
__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
268268
{
269269
struct mid_q_entry *mid;
270270
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
@@ -281,6 +281,10 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
281281
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
282282
(mid->command == shdr->Command)) {
283283
kref_get(&mid->refcount);
284+
if (dequeue) {
285+
list_del_init(&mid->qhead);
286+
mid->mid_flags |= MID_DELETED;
287+
}
284288
spin_unlock(&GlobalMid_Lock);
285289
return mid;
286290
}
@@ -289,6 +293,18 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
289293
return NULL;
290294
}
291295

296+
static struct mid_q_entry *
297+
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
298+
{
299+
return __smb2_find_mid(server, buf, false);
300+
}
301+
302+
static struct mid_q_entry *
303+
smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
304+
{
305+
return __smb2_find_mid(server, buf, true);
306+
}
307+
292308
static void
293309
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
294310
{
@@ -4404,7 +4420,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
44044420
cifs_dbg(FYI, "%s: server returned error %d\n",
44054421
__func__, rdata->result);
44064422
/* normal error on read response */
4407-
dequeue_mid(mid, false);
4423+
if (is_offloaded)
4424+
mid->mid_state = MID_RESPONSE_RECEIVED;
4425+
else
4426+
dequeue_mid(mid, false);
44084427
return 0;
44094428
}
44104429

@@ -4428,7 +4447,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
44284447
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
44294448
__func__, data_offset);
44304449
rdata->result = -EIO;
4431-
dequeue_mid(mid, rdata->result);
4450+
if (is_offloaded)
4451+
mid->mid_state = MID_RESPONSE_MALFORMED;
4452+
else
4453+
dequeue_mid(mid, rdata->result);
44324454
return 0;
44334455
}
44344456

@@ -4444,21 +4466,30 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
44444466
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
44454467
__func__, data_offset);
44464468
rdata->result = -EIO;
4447-
dequeue_mid(mid, rdata->result);
4469+
if (is_offloaded)
4470+
mid->mid_state = MID_RESPONSE_MALFORMED;
4471+
else
4472+
dequeue_mid(mid, rdata->result);
44484473
return 0;
44494474
}
44504475

44514476
if (data_len > page_data_size - pad_len) {
44524477
/* data_len is corrupt -- discard frame */
44534478
rdata->result = -EIO;
4454-
dequeue_mid(mid, rdata->result);
4479+
if (is_offloaded)
4480+
mid->mid_state = MID_RESPONSE_MALFORMED;
4481+
else
4482+
dequeue_mid(mid, rdata->result);
44554483
return 0;
44564484
}
44574485

44584486
rdata->result = init_read_bvec(pages, npages, page_data_size,
44594487
cur_off, &bvec);
44604488
if (rdata->result != 0) {
4461-
dequeue_mid(mid, rdata->result);
4489+
if (is_offloaded)
4490+
mid->mid_state = MID_RESPONSE_MALFORMED;
4491+
else
4492+
dequeue_mid(mid, rdata->result);
44624493
return 0;
44634494
}
44644495

@@ -4473,7 +4504,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
44734504
/* read response payload cannot be in both buf and pages */
44744505
WARN_ONCE(1, "buf can not contain only a part of read data");
44754506
rdata->result = -EIO;
4476-
dequeue_mid(mid, rdata->result);
4507+
if (is_offloaded)
4508+
mid->mid_state = MID_RESPONSE_MALFORMED;
4509+
else
4510+
dequeue_mid(mid, rdata->result);
44774511
return 0;
44784512
}
44794513

@@ -4484,7 +4518,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
44844518
if (length < 0)
44854519
return length;
44864520

4487-
dequeue_mid(mid, false);
4521+
if (is_offloaded)
4522+
mid->mid_state = MID_RESPONSE_RECEIVED;
4523+
else
4524+
dequeue_mid(mid, false);
44884525
return length;
44894526
}
44904527

@@ -4513,7 +4550,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
45134550
}
45144551

45154552
dw->server->lstrp = jiffies;
4516-
mid = smb2_find_mid(dw->server, dw->buf);
4553+
mid = smb2_find_dequeue_mid(dw->server, dw->buf);
45174554
if (mid == NULL)
45184555
cifs_dbg(FYI, "mid not found\n");
45194556
else {

0 commit comments

Comments
 (0)