]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
generator: cap block s2length at the negotiated checksum length
authorAndrew Tridgell <andrew@tridgell.net>
Thu, 4 Jun 2026 04:04:47 +0000 (14:04 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Thu, 4 Jun 2026 04:33:20 +0000 (14:33 +1000)
sum_sizes_sqroot() capped the strong-sum length at SUM_LENGTH (16), the
legacy MD4/MD5 digest size.  Since 0902b52f the sum2 array elements are
xfer_sum_len bytes and the sender rejects a sums header whose s2length
exceeds xfer_sum_len.  When the negotiated transfer checksum is shorter
than 16 bytes -- xxh64 (8), used when the build's libxxhash lacks
xxh128/xxh3 (e.g. Ubuntu 20.04) -- the generator still emitted s2length
up to 16, so --append-verify and other full-checksum (redo) transfers
died with "Invalid checksum length 16 [sender]" (protocol incompatibility).

Cap s2length at MIN(SUM_LENGTH, xfer_sum_len): unchanged for any checksum
>= 16 bytes (md5/xxh128/sha1), corrected for short ones.  Also closes a
latent over-read of the xfer_sum_len-sized digest buffer.

generator.c

index 4d4ae72e38817494dc28a4748b52d6e443eced14..83c4c128b9add264423c7839f56c328664b5be17 100644 (file)
@@ -66,6 +66,7 @@ extern int inplace;
 extern int append_mode;
 extern int make_backups;
 extern int csum_length;
+extern int xfer_sum_len;
 extern int ignore_times;
 extern int size_only;
 extern OFF_T max_size;
@@ -697,6 +698,11 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
 {
        int32 blength;
        int s2length;
+       /* The strong sum can be no longer than the negotiated checksum digest:
+        * a short checksum (e.g. xxh64 = 8 bytes, when xxh128/xxh3 are absent)
+        * makes xfer_sum_len < SUM_LENGTH, and the sender rejects an s2length
+        * larger than xfer_sum_len (io.c). */
+       int max_s2length = MIN(SUM_LENGTH, xfer_sum_len);
        int64 l;
 
        if (len < 0) {
@@ -731,7 +737,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
        if (protocol_version < 27) {
                s2length = csum_length;
        } else if (csum_length == SUM_LENGTH) {
-               s2length = SUM_LENGTH;
+               s2length = max_s2length;
        } else {
                int32 c;
                int b = BLOCKSUM_BIAS;
@@ -740,7 +746,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
                /* add a bit, subtract rollsum, round up. */
                s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */
                s2length = MAX(s2length, csum_length);
-               s2length = MIN(s2length, SUM_LENGTH);
+               s2length = MIN(s2length, max_s2length);
        }
 
        sum->flength    = len;