From 032eed6181423c8c5fae5f8f75018284ea4e5325 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 15 Jun 2026 16:14:38 +1000 Subject: [PATCH] match: re-check .len == l before substituting want_i in hash_search The check_want_i adjacent-match optimisation substitutes i = want_i after verifying sum1 and sum2, but -- unlike the main chain loop and the aligned_i path -- did not re-check s->sums[want_i].len == l. A hostile peer acting as the generator against a daemon-as-sender can set s2length=0 (read_sum_head only enforces >= 0, so the sum2 memcmp is a no-op) and craft count=2, blength=len+1, remainder=len with both sum1 set to the file's rolling checksum. The chain head (.len=remainder=len) passes the l==.len gate; want_i=0 (.len=blength=len+1) is then substituted unchecked. After matched(), offset advances to len, k = MIN(blength, len-offset) = 0, map_ptr(...,0) returns NULL, and the rolling- checksum trim dereferences map[0] -- a remote unauthenticated SEGV of the per-connection daemon child against any module serving a non-empty regular file. Add the missing length re-check, matching the chain loop and aligned_i path. (cherry picked from commit aad82d77aae098c8d8529f69614a0ffcbfbbb5d3) (cherry picked from commit 8c1d0d3820b910e668a172e281393d4364cadc0d) --- match.c | 1 + 1 file changed, 1 insertion(+) diff --git a/match.c b/match.c index 10e60bd3..45b39b57 100644 --- a/match.c +++ b/match.c @@ -293,6 +293,7 @@ static void hash_search(int f,struct sum_struct *s, && (!updating_basis_file || s->sums[want_i].offset >= offset || s->sums[want_i].flags & SUMFLG_SAME_OFFSET) && sum == s->sums[want_i].sum1 + && l == s->sums[want_i].len && memcmp(sum2, sum2_at(s, want_i), s->s2length) == 0) { /* we've found an adjacent match - the RLL coder * will be happy */