]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: compress: fix counting in LZ77 match finding
authorEnzo Matsumiya <ematsumiya@suse.de>
Mon, 13 Apr 2026 19:07:08 +0000 (16:07 -0300)
committerSteve French <stfrench@microsoft.com>
Wed, 22 Apr 2026 14:55:34 +0000 (09:55 -0500)
- lz77_match_len() increments @cur before checking for equality,
  leading to off-by-one match len in some cases.

  Fix by moving pointers increment to inside the loop.
  Also rename @wnd arg to @match (more accurate name).
- both lz77_match_len() and lz77_compress() checked for
  "buf + step < end" when the correct is "<=" for such cases.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/compress/lz77.c

index c1e7fada6e61c425818be03563deddd1a18ebc94..61cdf1c146127283f781597a8a5599b96d7048c3 100644 (file)
@@ -48,17 +48,17 @@ static __always_inline void lz77_write32(u32 *ptr, u32 v)
        put_unaligned_le32(v, ptr);
 }
 
-static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end)
+static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end)
 {
        const void *start = cur;
        u64 diff;
 
        /* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */
        do {
-               diff = lz77_read64(cur) ^ lz77_read64(wnd);
+               diff = lz77_read64(cur) ^ lz77_read64(match);
                if (!diff) {
                        cur += LZ77_STEP_SIZE;
-                       wnd += LZ77_STEP_SIZE;
+                       match += LZ77_STEP_SIZE;
 
                        continue;
                }
@@ -67,10 +67,13 @@ static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, cons
                cur += count_trailing_zeros(diff) >> 3;
 
                return (cur - start);
-       } while (likely(cur + LZ77_STEP_SIZE < end));
+       } while (likely(cur + LZ77_STEP_SIZE <= end));
 
-       while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++))
-               ;
+       /* Fallback to byte-by-byte comparison for last <8 bytes. */
+       while (cur < end && lz77_read8(cur) == lz77_read8(match)) {
+               cur++;
+               match++;
+       }
 
        return (cur - start);
 }
@@ -195,7 +198,7 @@ noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen)
                        flag_pos = dstp;
                        dstp += 4;
                }
-       } while (likely(srcp + LZ77_STEP_SIZE < end));
+       } while (likely(srcp + LZ77_STEP_SIZE <= end));
 
        while (srcp < end) {
                u32 c = umin(end - srcp, 32 - flag_count);