Skip to content

Commit fc6c6a3

Browse files
namjaejeonSteve French
authored andcommitted
ksmbd: fix out-of-bound read in parse_lease_state()
This bug is in parse_lease_state, and it is caused by the missing check of `struct create_context`. When the ksmbd traverses the create_contexts, it doesn't check if the field of `NameOffset` and `Next` is valid, The KASAN message is following: [ 6.664323] BUG: KASAN: slab-out-of-bounds in parse_lease_state+0x7d/0x280 [ 6.664738] Read of size 2 at addr ffff888005c08988 by task kworker/0:3/103 ... [ 6.666644] Call Trace: [ 6.666796] <TASK> [ 6.666933] dump_stack_lvl+0x33/0x50 [ 6.667167] print_report+0xcc/0x620 [ 6.667903] kasan_report+0xae/0xe0 [ 6.668374] kasan_check_range+0x35/0x1b0 [ 6.668621] parse_lease_state+0x7d/0x280 [ 6.668868] smb2_open+0xbe8/0x4420 [ 6.675137] handle_ksmbd_work+0x282/0x820 Use smb2_find_context_vals() to find smb2 create request lease context. smb2_find_context_vals validate create context fields. Cc: stable@vger.kernel.org Reported-by: Chih-Yen Chang <cc85nod@gmail.com> Tested-by: Chih-Yen Chang <cc85nod@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent f1a4118 commit fc6c6a3

File tree

1 file changed

+24
-42
lines changed

1 file changed

+24
-42
lines changed

fs/smb/server/oplock.c

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,56 +1415,38 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
14151415
*/
14161416
struct lease_ctx_info *parse_lease_state(void *open_req)
14171417
{
1418-
char *data_offset;
14191418
struct create_context *cc;
1420-
unsigned int next = 0;
1421-
char *name;
1422-
bool found = false;
14231419
struct smb2_create_req *req = (struct smb2_create_req *)open_req;
1424-
struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info),
1425-
GFP_KERNEL);
1420+
struct lease_ctx_info *lreq;
1421+
1422+
cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
1423+
if (IS_ERR_OR_NULL(cc))
1424+
return NULL;
1425+
1426+
lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);
14261427
if (!lreq)
14271428
return NULL;
14281429

1429-
data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset);
1430-
cc = (struct create_context *)data_offset;
1431-
do {
1432-
cc = (struct create_context *)((char *)cc + next);
1433-
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
1434-
if (le16_to_cpu(cc->NameLength) != 4 ||
1435-
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
1436-
next = le32_to_cpu(cc->Next);
1437-
continue;
1438-
}
1439-
found = true;
1440-
break;
1441-
} while (next != 0);
1430+
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
1431+
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
14421432

1443-
if (found) {
1444-
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
1445-
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
1446-
1447-
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1448-
lreq->req_state = lc->lcontext.LeaseState;
1449-
lreq->flags = lc->lcontext.LeaseFlags;
1450-
lreq->duration = lc->lcontext.LeaseDuration;
1451-
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
1452-
SMB2_LEASE_KEY_SIZE);
1453-
lreq->version = 2;
1454-
} else {
1455-
struct create_lease *lc = (struct create_lease *)cc;
1433+
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1434+
lreq->req_state = lc->lcontext.LeaseState;
1435+
lreq->flags = lc->lcontext.LeaseFlags;
1436+
lreq->duration = lc->lcontext.LeaseDuration;
1437+
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
1438+
SMB2_LEASE_KEY_SIZE);
1439+
lreq->version = 2;
1440+
} else {
1441+
struct create_lease *lc = (struct create_lease *)cc;
14561442

1457-
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1458-
lreq->req_state = lc->lcontext.LeaseState;
1459-
lreq->flags = lc->lcontext.LeaseFlags;
1460-
lreq->duration = lc->lcontext.LeaseDuration;
1461-
lreq->version = 1;
1462-
}
1463-
return lreq;
1443+
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1444+
lreq->req_state = lc->lcontext.LeaseState;
1445+
lreq->flags = lc->lcontext.LeaseFlags;
1446+
lreq->duration = lc->lcontext.LeaseDuration;
1447+
lreq->version = 1;
14641448
}
1465-
1466-
kfree(lreq);
1467-
return NULL;
1449+
return lreq;
14681450
}
14691451

14701452
/**

0 commit comments

Comments
 (0)