Skip to content

Commit 442ff9e

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: add validation in smb2 negotiate
This patch add validation to check request buffer check in smb2 negotiate and fix null pointer deferencing oops in smb3_preauth_hash_rsp() that found from manual test. Cc: Tom Talpey <[email protected]> Cc: Ronnie Sahlberg <[email protected]> Cc: Ralph Böhme <[email protected]> Cc: Hyunchul Lee <[email protected]> Cc: Sergey Senozhatsky <[email protected]> Reviewed-by: Ralph Boehme <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 9496e26 commit 442ff9e

File tree

2 files changed

+68
-6
lines changed

2 files changed

+68
-6
lines changed

fs/ksmbd/smb2pdu.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
10671067
struct smb2_negotiate_req *req = work->request_buf;
10681068
struct smb2_negotiate_rsp *rsp = work->response_buf;
10691069
int rc = 0;
1070+
unsigned int smb2_buf_len, smb2_neg_size;
10701071
__le32 status;
10711072

10721073
ksmbd_debug(SMB, "Received negotiate request\n");
@@ -1084,6 +1085,44 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
10841085
goto err_out;
10851086
}
10861087

1088+
smb2_buf_len = get_rfc1002_len(work->request_buf);
1089+
smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects) - 4;
1090+
if (smb2_neg_size > smb2_buf_len) {
1091+
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1092+
rc = -EINVAL;
1093+
goto err_out;
1094+
}
1095+
1096+
if (conn->dialect == SMB311_PROT_ID) {
1097+
unsigned int nego_ctxt_off = le32_to_cpu(req->NegotiateContextOffset);
1098+
1099+
if (smb2_buf_len < nego_ctxt_off) {
1100+
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1101+
rc = -EINVAL;
1102+
goto err_out;
1103+
}
1104+
1105+
if (smb2_neg_size > nego_ctxt_off) {
1106+
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1107+
rc = -EINVAL;
1108+
goto err_out;
1109+
}
1110+
1111+
if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
1112+
nego_ctxt_off) {
1113+
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1114+
rc = -EINVAL;
1115+
goto err_out;
1116+
}
1117+
} else {
1118+
if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
1119+
smb2_buf_len) {
1120+
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
1121+
rc = -EINVAL;
1122+
goto err_out;
1123+
}
1124+
}
1125+
10871126
conn->cli_cap = le32_to_cpu(req->Capabilities);
10881127
switch (conn->dialect) {
10891128
case SMB311_PROT_ID:
@@ -8244,7 +8283,8 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
82448283

82458284
WORK_BUFFERS(work, req, rsp);
82468285

8247-
if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE)
8286+
if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE &&
8287+
conn->preauth_info)
82488288
ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp,
82498289
conn->preauth_info->Preauth_HashValue);
82508290

fs/ksmbd/smb_common.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,12 @@ static bool supported_protocol(int idx)
169169
idx <= server_conf.max_protocol);
170170
}
171171

172-
static char *next_dialect(char *dialect, int *next_off)
172+
static char *next_dialect(char *dialect, int *next_off, int bcount)
173173
{
174174
dialect = dialect + *next_off;
175-
*next_off = strlen(dialect);
175+
*next_off = strnlen(dialect, bcount);
176+
if (dialect[*next_off] != '\0')
177+
return NULL;
176178
return dialect;
177179
}
178180

@@ -187,7 +189,9 @@ static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count)
187189
dialect = cli_dialects;
188190
bcount = le16_to_cpu(byte_count);
189191
do {
190-
dialect = next_dialect(dialect, &next);
192+
dialect = next_dialect(dialect, &next, bcount);
193+
if (!dialect)
194+
break;
191195
ksmbd_debug(SMB, "client requested dialect %s\n",
192196
dialect);
193197
if (!strcmp(dialect, smb1_protos[i].name)) {
@@ -235,13 +239,22 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
235239

236240
static int ksmbd_negotiate_smb_dialect(void *buf)
237241
{
238-
__le32 proto;
242+
int smb_buf_length = get_rfc1002_len(buf);
243+
__le32 proto = ((struct smb2_hdr *)buf)->ProtocolId;
239244

240-
proto = ((struct smb2_hdr *)buf)->ProtocolId;
241245
if (proto == SMB2_PROTO_NUMBER) {
242246
struct smb2_negotiate_req *req;
247+
int smb2_neg_size =
248+
offsetof(struct smb2_negotiate_req, Dialects) - 4;
243249

244250
req = (struct smb2_negotiate_req *)buf;
251+
if (smb2_neg_size > smb_buf_length)
252+
goto err_out;
253+
254+
if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
255+
smb_buf_length)
256+
goto err_out;
257+
245258
return ksmbd_lookup_dialect_by_id(req->Dialects,
246259
req->DialectCount);
247260
}
@@ -251,10 +264,19 @@ static int ksmbd_negotiate_smb_dialect(void *buf)
251264
struct smb_negotiate_req *req;
252265

253266
req = (struct smb_negotiate_req *)buf;
267+
if (le16_to_cpu(req->ByteCount) < 2)
268+
goto err_out;
269+
270+
if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 +
271+
le16_to_cpu(req->ByteCount) > smb_buf_length) {
272+
goto err_out;
273+
}
274+
254275
return ksmbd_lookup_dialect_by_name(req->DialectsArray,
255276
req->ByteCount);
256277
}
257278

279+
err_out:
258280
return BAD_PROT_ID;
259281
}
260282

0 commit comments

Comments
 (0)