mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
ksmbd: add negotiate context verification
This patch add negotiate context verification code to check bounds. Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
9223958816
commit
af320a7390
@ -835,10 +835,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
|
||||
build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt,
|
||||
conn->cipher_type);
|
||||
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
|
||||
ctxt_size += sizeof(struct smb2_encryption_neg_context);
|
||||
ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2;
|
||||
/* Round to 8 byte boundary */
|
||||
pneg_ctxt +=
|
||||
round_up(sizeof(struct smb2_encryption_neg_context),
|
||||
round_up(sizeof(struct smb2_encryption_neg_context) + 2,
|
||||
8);
|
||||
}
|
||||
|
||||
@ -850,9 +850,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
|
||||
build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt,
|
||||
conn->compress_algorithm);
|
||||
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
|
||||
ctxt_size += sizeof(struct smb2_compression_ctx);
|
||||
ctxt_size += sizeof(struct smb2_compression_ctx) + 2;
|
||||
/* Round to 8 byte boundary */
|
||||
pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx), 8);
|
||||
pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2,
|
||||
8);
|
||||
}
|
||||
|
||||
if (conn->posix_ext_supported) {
|
||||
@ -881,16 +882,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int decode_encrypt_ctxt(struct ksmbd_conn *conn,
|
||||
struct smb2_encryption_neg_context *pneg_ctxt)
|
||||
static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
|
||||
struct smb2_encryption_neg_context *pneg_ctxt,
|
||||
int len_of_ctxts)
|
||||
{
|
||||
int i;
|
||||
int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
|
||||
int i, cphs_size = cph_cnt * sizeof(__le16);
|
||||
|
||||
conn->cipher_type = 0;
|
||||
|
||||
if (sizeof(struct smb2_encryption_neg_context) + cphs_size >
|
||||
len_of_ctxts) {
|
||||
pr_err("Invalid cipher count(%d)\n", cph_cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
for (i = 0; i < cph_cnt; i++) {
|
||||
if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM ||
|
||||
@ -903,90 +911,88 @@ static int decode_encrypt_ctxt(struct ksmbd_conn *conn,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Return encrypt context size in request.
|
||||
* So need to plus extra number of ciphers size.
|
||||
*/
|
||||
return sizeof(struct smb2_encryption_neg_context) +
|
||||
((cph_cnt - 1) * 2);
|
||||
}
|
||||
|
||||
static int decode_compress_ctxt(struct ksmbd_conn *conn,
|
||||
struct smb2_compression_ctx *pneg_ctxt)
|
||||
static void decode_compress_ctxt(struct ksmbd_conn *conn,
|
||||
struct smb2_compression_ctx *pneg_ctxt)
|
||||
{
|
||||
int algo_cnt = le16_to_cpu(pneg_ctxt->CompressionAlgorithmCount);
|
||||
|
||||
conn->compress_algorithm = SMB3_COMPRESS_NONE;
|
||||
|
||||
/*
|
||||
* Return compression context size in request.
|
||||
* So need to plus extra number of CompressionAlgorithms size.
|
||||
*/
|
||||
return sizeof(struct smb2_compression_ctx) +
|
||||
((algo_cnt - 1) * 2);
|
||||
}
|
||||
|
||||
static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
|
||||
struct smb2_negotiate_req *req)
|
||||
{
|
||||
int i = 0;
|
||||
__le32 status = 0;
|
||||
/* +4 is to account for the RFC1001 len field */
|
||||
char *pneg_ctxt = (char *)req +
|
||||
le32_to_cpu(req->NegotiateContextOffset) + 4;
|
||||
__le16 *ContextType = (__le16 *)pneg_ctxt;
|
||||
struct smb2_neg_context *pctx = (struct smb2_neg_context *)((char *)req + 4);
|
||||
int i = 0, len_of_ctxts;
|
||||
int offset = le32_to_cpu(req->NegotiateContextOffset);
|
||||
int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
|
||||
int ctxt_size;
|
||||
int len_of_smb = be32_to_cpu(req->hdr.smb2_buf_length);
|
||||
__le32 status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);
|
||||
if (len_of_smb <= offset) {
|
||||
ksmbd_debug(SMB, "Invalid response: negotiate context offset\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
len_of_ctxts = len_of_smb - offset;
|
||||
|
||||
ksmbd_debug(SMB, "negotiate context count = %d\n", neg_ctxt_cnt);
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
while (i++ < neg_ctxt_cnt) {
|
||||
if (*ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
|
||||
int clen;
|
||||
|
||||
/* check that offset is not beyond end of SMB */
|
||||
if (len_of_ctxts == 0)
|
||||
break;
|
||||
|
||||
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)
|
||||
break;
|
||||
|
||||
if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
|
||||
ksmbd_debug(SMB,
|
||||
"deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");
|
||||
if (conn->preauth_info->Preauth_HashId)
|
||||
break;
|
||||
|
||||
status = decode_preauth_ctxt(conn,
|
||||
(struct smb2_preauth_neg_context *)pneg_ctxt);
|
||||
pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8;
|
||||
} else if (*ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
|
||||
(struct smb2_preauth_neg_context *)pctx);
|
||||
if (status != STATUS_SUCCESS)
|
||||
break;
|
||||
} else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
|
||||
ksmbd_debug(SMB,
|
||||
"deassemble SMB2_ENCRYPTION_CAPABILITIES context\n");
|
||||
if (conn->cipher_type)
|
||||
break;
|
||||
|
||||
ctxt_size = decode_encrypt_ctxt(conn,
|
||||
(struct smb2_encryption_neg_context *)pneg_ctxt);
|
||||
pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8;
|
||||
} else if (*ContextType == SMB2_COMPRESSION_CAPABILITIES) {
|
||||
decode_encrypt_ctxt(conn,
|
||||
(struct smb2_encryption_neg_context *)pctx,
|
||||
len_of_ctxts);
|
||||
} else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {
|
||||
ksmbd_debug(SMB,
|
||||
"deassemble SMB2_COMPRESSION_CAPABILITIES context\n");
|
||||
if (conn->compress_algorithm)
|
||||
break;
|
||||
|
||||
ctxt_size = decode_compress_ctxt(conn,
|
||||
(struct smb2_compression_ctx *)pneg_ctxt);
|
||||
pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8;
|
||||
} else if (*ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) {
|
||||
decode_compress_ctxt(conn,
|
||||
(struct smb2_compression_ctx *)pctx);
|
||||
} else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) {
|
||||
ksmbd_debug(SMB,
|
||||
"deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n");
|
||||
ctxt_size = sizeof(struct smb2_netname_neg_context);
|
||||
ctxt_size += DIV_ROUND_UP(le16_to_cpu(((struct smb2_netname_neg_context *)
|
||||
pneg_ctxt)->DataLength), 8) * 8;
|
||||
pneg_ctxt += ctxt_size;
|
||||
} else if (*ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) {
|
||||
} else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) {
|
||||
ksmbd_debug(SMB,
|
||||
"deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");
|
||||
conn->posix_ext_supported = true;
|
||||
pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_posix_neg_context), 8) * 8;
|
||||
}
|
||||
ContextType = (__le16 *)pneg_ctxt;
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
break;
|
||||
/* offsets must be 8 byte aligned */
|
||||
clen = (clen + 7) & ~0x7;
|
||||
offset = clen + sizeof(struct smb2_neg_context);
|
||||
len_of_ctxts -= clen + sizeof(struct smb2_neg_context);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ struct smb2_encryption_neg_context {
|
||||
__le32 Reserved;
|
||||
/* CipherCount usally 2, but can be 3 when AES256-GCM enabled */
|
||||
__le16 CipherCount; /* AES-128-GCM and AES-128-CCM by default */
|
||||
__le16 Ciphers[1];
|
||||
__le16 Ciphers[];
|
||||
} __packed;
|
||||
|
||||
#define SMB3_COMPRESS_NONE cpu_to_le16(0x0000)
|
||||
@ -314,7 +314,7 @@ struct smb2_compression_ctx {
|
||||
__le16 CompressionAlgorithmCount;
|
||||
__u16 Padding;
|
||||
__le32 Reserved1;
|
||||
__le16 CompressionAlgorithms[1];
|
||||
__le16 CompressionAlgorithms[];
|
||||
} __packed;
|
||||
|
||||
#define POSIX_CTXT_DATA_LEN 16
|
||||
@ -329,7 +329,7 @@ struct smb2_netname_neg_context {
|
||||
__le16 ContextType; /* 0x100 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 NetName[0]; /* hostname of target converted to UCS-2 */
|
||||
__le16 NetName[]; /* hostname of target converted to UCS-2 */
|
||||
} __packed;
|
||||
|
||||
struct smb2_negotiate_rsp {
|
||||
|
Loading…
Reference in New Issue
Block a user