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: a08de24c2b85 ("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>
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;