Re: [PATCH 1/2] smb: compress: reject Pattern_V1 when not negotiated

ChenXiaoSong <[email protected]> Sat, 1 Aug 2026 17:42:28 +0800
Newsgroups org.kernel.vger.linux-cifs
Message-ID <[email protected]>
Reviewed-by: ChenXiaoSong <[email protected]>
Fixes: a08de24c2b85 ("ksmbd: negotiate and decode SMB2 compression")

See MS-SMB2 3.3.5.2.1.2

By the way, smb_compression_decompress() has too many parameters, 
perhaps we can put them into a structure in the future.

在 2026/8/1 13:19, Anatolii Shumak 写道:
> Pattern_V1 is an optional chained payload type selected during SMB 3.1.1
> compression negotiate. conn->compress_pattern was only consulted when
> building responses, so a peer that negotiated LZ77 with chained support
> could still submit Pattern payloads on the receive path.
> 
> Pass allow_pattern through smb_compression_decompress() and reject
> SMB3_COMPRESS_PATTERN in the chained decoder when it is false.
> 
> Link: https://github.com/namjaejeon/ksmbd/issues/529
> Signed-off-by: Anatolii Shumak <[email protected]>
> ---
>   fs/smb/common/compress/compress.c | 11 ++++++++---
>   fs/smb/common/compress/compress.h |  3 ++-
>   fs/smb/server/compress.c          |  1 +
>   3 files changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/smb/common/compress/compress.c b/fs/smb/common/compress/compress.c
> index b07a317597a4..a4123c8f1c0a 100644
> --- a/fs/smb/common/compress/compress.c
> +++ b/fs/smb/common/compress/compress.c
> @@ -95,6 +95,7 @@ static int smb_decompress_lz77_payload(const u8 **src, u32 *slen, u8 **dst,
>   }
>   
>   static int smb_decompress_chained(__le16 alg, bool allow_chained,
> +				  bool allow_pattern,
>   				  const struct smb2_compression_hdr *hdr,
>   				  u32 slen, void *dst, u32 dlen)
>   {
> @@ -143,6 +144,8 @@ static int smb_decompress_chained(__le16 alg, bool allow_chained,
>   			rc = smb_decompress_none(&src, &remaining, &out,
>   						 &out_remaining, len);
>   		} else if (payload_alg == SMB3_COMPRESS_PATTERN) {
> +			if (!allow_pattern)
> +				return -EINVAL;
>   			rc = smb_decompress_pattern(&src, &remaining, &out,
>   						    &out_remaining, len);
>   		} else if (payload_alg == alg && alg == SMB3_COMPRESS_LZ77) {
> @@ -185,6 +188,7 @@ static int smb_decompress_unchained(__le16 alg,
>    * smb_compression_decompress() - decode an SMB2 compression transform
>    * @alg: negotiated general-purpose compression algorithm
>    * @allow_chained: whether chained transforms were negotiated
> + * @allow_pattern: whether Pattern_V1 payloads were negotiated
>    * @src: transform header followed by compressed payload data
>    * @slen: total number of bytes available at @src
>    * @dst: output buffer for the reconstructed SMB2 message
> @@ -197,7 +201,8 @@ static int smb_decompress_unchained(__le16 alg,
>    * Return: 0 on success, otherwise a negative errno.
>    */
>   int smb_compression_decompress(__le16 alg, bool allow_chained,
> -			       const void *src, u32 slen, void *dst, u32 dlen)
> +			       bool allow_pattern, const void *src, u32 slen,
> +			       void *dst, u32 dlen)
>   {
>   	const struct smb2_compression_hdr *hdr = src;
>   
> @@ -207,8 +212,8 @@ int smb_compression_decompress(__le16 alg, bool allow_chained,
>   		return -EINVAL;
>   
>   	if (hdr->Flags == cpu_to_le16(SMB2_COMPRESSION_FLAG_CHAINED))
> -		return smb_decompress_chained(alg, allow_chained, hdr, slen,
> -					      dst, dlen);
> +		return smb_decompress_chained(alg, allow_chained, allow_pattern,
> +					      hdr, slen, dst, dlen);
>   
>   	if (hdr->Flags != cpu_to_le16(SMB2_COMPRESSION_FLAG_NONE))
>   		return -EINVAL;
> diff --git a/fs/smb/common/compress/compress.h b/fs/smb/common/compress/compress.h
> index 7ace3bf4b664..d6916669f887 100644
> --- a/fs/smb/common/compress/compress.h
> +++ b/fs/smb/common/compress/compress.h
> @@ -20,7 +20,8 @@ static __always_inline bool smb_compress_alg_valid(__le16 alg, bool valid_none)
>   }
>   
>   int smb_compression_decompress(__le16 alg, bool allow_chained,
> -			       const void *src, u32 slen, void *dst, u32 dlen);
> +			       bool allow_pattern, const void *src, u32 slen,
> +			       void *dst, u32 dlen);
>   int smb_compression_compress_chained(__le16 alg, bool allow_pattern,
>   				     const void *src, u32 slen,
>   				     void *dst, u32 *dlen);
> diff --git a/fs/smb/server/compress.c b/fs/smb/server/compress.c
> index 95e48fa6b448..821299888ad3 100644
> --- a/fs/smb/server/compress.c
> +++ b/fs/smb/server/compress.c
> @@ -69,6 +69,7 @@ int ksmbd_decompress_request(struct ksmbd_conn *conn)
>   	*(__be32 *)out = cpu_to_be32(out_size);
>   	rc = smb_compression_decompress(conn->compress_algorithm,
>   					conn->compress_chained,
> +					conn->compress_pattern,
>   					buf, pdu_size, out + 4, out_size);
>   	if (rc) {
>   		kvfree(out);

-- 
ChenXiaoSong <[email protected]>
Chinese Homepage: https://chenxiaosong.com
English Homepage: https://chenxiaosong.com/en