diff --git a/rsync-3.1.3-fix-cve-2026-43618.patch b/rsync-3.1.3-fix-cve-2026-43618.patch new file mode 100644 index 0000000..272687b --- /dev/null +++ b/rsync-3.1.3-fix-cve-2026-43618.patch @@ -0,0 +1,174 @@ +From 9ec57dd61762175a5fef11b66f36cbe6bd451178 Mon Sep 17 00:00:00 2001 +From: Andrew Tridgell +Date: Wed, 29 Apr 2026 11:10:59 +1000 +Subject: [PATCH] token: harden compressed-token decoding against integer + overflow + +The receiver's three compressed-token decoders -- +recv_deflated_token (zlib), recv_zstd_token, and +recv_compressed_token (lz4) -- accumulated rx_token (a 32-bit +signed counter) without overflow checking. A malicious sender +could craft a compressed-token stream that walked rx_token past +INT32_MAX, with careful manipulation leaking process memory +contents to the wire (environment variables, passwords, heap +pointers, library pointers -- significantly weakening ASLR +and facilitating further exploitation). + +Cap rx_token at MAX_TOKEN_INDEX = 0x7ffffffe. Fold the +bookkeeping into recv_compressed_token_num() and +recv_compressed_token_run() shared by all three decoders. Reject +negative or out-of-range token values explicitly. Also cap the +simple_recv_token literal-block length at the source: any +wire-supplied length > CHUNK_SIZE is ill-formed (the matching +simple_send_token never writes a chunk larger than CHUNK_SIZE), +so reject before looping on attacker-controlled bytes. + +Reach: an authenticated daemon connection with compression +enabled (the default for protocols >= 30 when both peers +advertise it). Disabling compression on the daemon +("refuse options = compress" in rsyncd.conf) is the available +workaround. + +Reporter: Omar Elsayed (seks99x). + +Co-Authored-By: Claude Opus 4.7 (1M context) +--- + receiver.c | 11 ++++++++- + token.c | 68 ++++++++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 63 insertions(+), 16 deletions(-) + +diff --git a/receiver.c b/receiver.c +index 6044836..59f9759 100644 +--- a/receiver.c ++++ b/receiver.c +@@ -305,7 +305,12 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, + } + } + +- while ((i = recv_token(f_in, &data)) != 0) { ++ while (1) { ++ data = NULL; ++ i = recv_token(f_in, &data); ++ if (i == 0) ++ break; ++ + if (INFO_GTE(PROGRESS, 1)) + show_progress(offset, total_size); + +@@ -313,6 +318,10 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, + maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH | MSK_ACTIVE_RECEIVER); + + if (i > 0) { ++ if (!data) { ++ rprintf(FERROR, "Invalid literal token with no data [%s]\n", who_am_i()); ++ exit_cleanup(RERR_PROTOCOL); ++ } + if (DEBUG_GTE(DELTASUM, 3)) { + rprintf(FINFO,"data recv %d at %s\n", + i, big_num(offset)); +diff --git a/token.c b/token.c +index f1299ee..fb722a5 100644 +--- a/token.c ++++ b/token.c +@@ -228,6 +228,14 @@ static int32 simple_recv_token(int f, char **data) + int32 i = read_int(f); + if (i <= 0) + return i; ++ /* simple_send_token caps each literal chunk at CHUNK_SIZE; ++ * reject anything larger so a hostile peer cannot drive the ++ * read_buf below past our static CHUNK_SIZE buffer. */ ++ if (i > CHUNK_SIZE) { ++ rprintf(FERROR, "invalid uncompressed token length %ld [%s]\n", ++ (long)i, who_am_i()); ++ exit_cleanup(RERR_PROTOCOL); ++ } + residue = i; + } + +@@ -441,9 +449,52 @@ static char *cbuf; + static char *dbuf; + + /* for decoding runs of tokens */ ++#define MAX_TOKEN_INDEX ((int32)0x7ffffffe) ++ + static int32 rx_token; + static int32 rx_run; + ++static NORETURN void invalid_compressed_token(void) ++{ ++ rprintf(FERROR, "invalid token number in compressed stream\n"); ++ exit_cleanup(RERR_PROTOCOL); ++} ++ ++static int32 recv_compressed_token_num(int f, int32 flag) ++{ ++ if (flag & TOKEN_REL) { ++ int32 incr = flag & 0x3f; ++ if (rx_token > MAX_TOKEN_INDEX - incr) ++ invalid_compressed_token(); ++ rx_token += incr; ++ flag >>= 6; ++ } else { ++ rx_token = read_int(f); ++ if (rx_token < 0 || rx_token > MAX_TOKEN_INDEX) ++ invalid_compressed_token(); ++ } ++ ++ if (flag & 1) { ++ rx_run = read_byte(f); ++ rx_run += read_byte(f) << 8; ++ if (rx_run <= 0 || rx_token > MAX_TOKEN_INDEX - rx_run) ++ invalid_compressed_token(); ++ recv_state = r_running; ++ } ++ ++ return -1 - rx_token; ++} ++ ++static int32 recv_compressed_token_run(void) ++{ ++ if (rx_run <= 0 || rx_token >= MAX_TOKEN_INDEX) ++ invalid_compressed_token(); ++ ++rx_token; ++ if (--rx_run == 0) ++ recv_state = r_idle; ++ return -1 - rx_token; ++} ++ + /* Receive a deflated token and inflate it */ + static int32 recv_deflated_token(int f, char **data) + { +@@ -535,17 +586,7 @@ static int32 recv_deflated_token(int f, char **data) + } + + /* here we have a token of some kind */ +- if (flag & TOKEN_REL) { +- rx_token += flag & 0x3f; +- flag >>= 6; +- } else +- rx_token = read_int(f); +- if (flag & 1) { +- rx_run = read_byte(f); +- rx_run += read_byte(f) << 8; +- recv_state = r_running; +- } +- return -1 - rx_token; ++ return recv_compressed_token_num(f, flag); + + case r_inflating: + rx_strm.next_out = (Bytef *)dbuf; +@@ -565,10 +606,7 @@ static int32 recv_deflated_token(int f, char **data) + break; + + case r_running: +- ++rx_token; +- if (--rx_run == 0) +- recv_state = r_idle; +- return -1 - rx_token; ++ return recv_compressed_token_run(); + } + } + } +-- +2.52.0 + diff --git a/rsync.spec b/rsync.spec index 0530be9..ca8e7bf 100644 --- a/rsync.spec +++ b/rsync.spec @@ -9,7 +9,7 @@ Summary: A program for synchronizing files over a network Name: rsync Version: 3.1.3 -Release: 26%{?dist} +Release: 27%{?dist} Group: Applications/Internet URL: http://rsync.samba.org/ @@ -67,6 +67,8 @@ Patch23: rsync-3.1.3-fix-cve-2026-29518.patch # https://github.com/RsyncProject/rsync/commit/3526884f # https://github.com/RsyncProject/rsync/commit/7192db98 Patch24: rsync-3.1.3-fix-cve-2026-29518-regressions.patch +# https://github.com/RsyncProject/rsync/commit/c44c90e9460c666c965446a8c0957f0b9fa4c66a +Patch25: rsync-3.1.3-fix-cve-2026-43618.patch %description Rsync uses a reliable algorithm to bring remote and host files into @@ -129,6 +131,7 @@ patch -p1 -i patches/copy-devices.diff %patch22 -p1 -b .cve-2026-41035 %patch23 -p1 -b .cve-2026-29518 %patch24 -p1 -b .cve-2026-29518-regressions +%patch25 -p1 -b .cve-2026-43618 %build %configure @@ -175,6 +178,10 @@ chmod -x support/* %systemd_postun_with_restart rsyncd.service %changelog +* Mon Jun 15 2026 Michal Ruprich - 3.1.3-27 +- Integer overflow in compressed-token decoding (CVE-2026-43618) +- Resolves: RHEL-174951 + * Thu May 28 2026 RHEL Packaging Agent - 3.1.3-26 - Resolves: RHEL-174950 - CVE-2026-29518 - TOCTOU symlink race in non-chrooted daemon modules