]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: validate compression Flags before kvmalloc
authorAnatolii Shumak <anatoliy.shumak@gmail.com>
Sat, 1 Aug 2026 05:19:53 +0000 (08:19 +0300)
committerSteve French <stfrench@microsoft.com>
Mon, 3 Aug 2026 16:21:22 +0000 (11:21 -0500)
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>
fs/smb/server/compress.c

index 821299888ad3adfc062fbd6df8af99f3ca11fa3e..7e13cae705e2f5ae77c8f0b26bbee445edc71032 100644 (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;