ksmbd: fix multiple out-of-bounds read during context decoding

[ Upstream commit 0512a5f89e1fae74251fde6893ff634f1c96c6fb ]

Check the remaining data length before accessing the context structure
to ensure that the entire structure is contained within the packet.
Additionally, since the context data length `ctxt_len` has already been
checked against the total packet length `len_of_ctxts`, update the
comparison to use `ctxt_len`.

Cc: stable@vger.kernel.org
Signed-off-by: Kuan-Ting Chen <h3xrabbit@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Kuan-Ting Chen 2023-12-19 00:33:55 +09:00 committed by Greg Kroah-Hartman
parent 61a306c1cc
commit 19b2b9af31

View File

@ -879,13 +879,14 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
struct smb2_preauth_neg_context *pneg_ctxt,
int len_of_ctxts)
int ctxt_len)
{
/*
* sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt,
* which may not be present. Only check for used HashAlgorithms[1].
*/
if (len_of_ctxts < 6)
if (ctxt_len <
sizeof(struct smb2_neg_context) + 6)
return STATUS_INVALID_PARAMETER;
if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
@ -897,15 +898,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
struct smb2_encryption_neg_context *pneg_ctxt,
int len_of_ctxts)
int ctxt_len)
{
int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
int i, cphs_size = cph_cnt * sizeof(__le16);
int cph_cnt;
int i, cphs_size;
if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) {
pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n");
return;
}
conn->cipher_type = 0;
cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
cphs_size = cph_cnt * sizeof(__le16);
if (sizeof(struct smb2_encryption_neg_context) + cphs_size >
len_of_ctxts) {
ctxt_len) {
pr_err("Invalid cipher count(%d)\n", cph_cnt);
return;
}
@ -953,15 +962,22 @@ static void decode_compress_ctxt(struct ksmbd_conn *conn,
static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
struct smb2_signing_capabilities *pneg_ctxt,
int len_of_ctxts)
int ctxt_len)
{
int sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
int i, sign_alos_size = sign_algo_cnt * sizeof(__le16);
int sign_algo_cnt;
int i, sign_alos_size;
if (sizeof(struct smb2_signing_capabilities) > ctxt_len) {
pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n");
return;
}
conn->signing_negotiated = false;
sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
sign_alos_size = sign_algo_cnt * sizeof(__le16);
if (sizeof(struct smb2_signing_capabilities) + sign_alos_size >
len_of_ctxts) {
ctxt_len) {
pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt);
return;
}
@ -999,18 +1015,16 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
len_of_ctxts = len_of_smb - offset;
while (i++ < neg_ctxt_cnt) {
int clen;
/* check that offset is not beyond end of SMB */
if (len_of_ctxts == 0)
break;
int clen, ctxt_len;
if (len_of_ctxts < sizeof(struct smb2_neg_context))
break;
pctx = (struct smb2_neg_context *)((char *)pctx + offset);
clen = le16_to_cpu(pctx->DataLength);
if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts)
ctxt_len = clen + sizeof(struct smb2_neg_context);
if (ctxt_len > len_of_ctxts)
break;
if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
@ -1021,7 +1035,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
status = decode_preauth_ctxt(conn,
(struct smb2_preauth_neg_context *)pctx,
len_of_ctxts);
ctxt_len);
if (status != STATUS_SUCCESS)
break;
} else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
@ -1032,7 +1046,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
decode_encrypt_ctxt(conn,
(struct smb2_encryption_neg_context *)pctx,
len_of_ctxts);
ctxt_len);
} else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {
ksmbd_debug(SMB,
"deassemble SMB2_COMPRESSION_CAPABILITIES context\n");
@ -1051,9 +1065,10 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
} else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) {
ksmbd_debug(SMB,
"deassemble SMB2_SIGNING_CAPABILITIES context\n");
decode_sign_cap_ctxt(conn,
(struct smb2_signing_capabilities *)pctx,
len_of_ctxts);
ctxt_len);
}
/* offsets must be 8 byte aligned */