ksmbd: validate compression Flags before kvmalloc

ksmbd_decompress_request() allocated the decompressed request buffer
before smb_compression_decompress() rejected unknown transform Flags or
chained mode when it was not negotiated. A remote peer could force a
transient multi-megabyte allocation that was immediately freed on
-EINVAL.

Validate CHAINED/NONE Flags and compress_chained before kvmalloc.

Link: https://github.com/namjaejeon/ksmbd/issues/529
Fixes: a08de24c2b ("ksmbd: negotiate and decode SMB2 compression")
Signed-off-by: Anatolii Shumak <anatoliy.shumak@gmail.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Anatolii Shumak 2026-08-01 08:19:53 +03:00 committed by Steve French
parent 0710dd0882
commit ba3afa8ccd

View File

@ -46,13 +46,22 @@ int ksmbd_decompress_request(struct ksmbd_conn *conn)
return -EINVAL;
orig_size = le32_to_cpu(hdr->OriginalCompressedSegmentSize);
/*
* For chained transforms the top-level header is only eight bytes; the
* Flags field overlays the first payload header. Reject unknown Flags
* and unnegotiated chained mode before allocating the output buffer.
*/
if (hdr->Flags == cpu_to_le16(SMB2_COMPRESSION_FLAG_CHAINED)) {
if (!conn->compress_chained)
return -EINVAL;
out_size = orig_size;
} else {
} else if (hdr->Flags == cpu_to_le16(SMB2_COMPRESSION_FLAG_NONE)) {
offset = le32_to_cpu(hdr->Offset);
if (offset > pdu_size - sizeof(*hdr) ||
check_add_overflow(orig_size, offset, &out_size))
return -EINVAL;
} else {
return -EINVAL;
}
max_allowed_pdu_size = SMB3_MAX_MSGSIZE + conn->vals->max_write_size;