[PATCH 2/2] ksmbd: validate compression Flags before kvmalloc

Anatolii Shumak <[email protected]> Sat, 1 Aug 2026 08:19:53 +0300
Newsgroups org.kernel.vger.linux-cifs
Message-ID <[email protected]>
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
Signed-off-by: Anatolii Shumak <[email protected]>
---
 fs/smb/server/compress.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/fs/smb/server/compress.c b/fs/smb/server/compress.c
index 821299888ad3..7e13cae705e2 100644
--- a/fs/smb/server/compress.c
+++ b/fs/smb/server/compress.c
@@ -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;
-- 
2.51.0.windows.2