]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
reject negative token values in compressed stream receivers
authorAndrew Tridgell <andrew@tridgell.net>
Tue, 30 Dec 2025 07:49:34 +0000 (18:49 +1100)
committerAndrew Tridgell <andrew@tridgell.net>
Tue, 30 Dec 2025 22:31:52 +0000 (09:31 +1100)
Validate that token numbers read from compressed streams are
non-negative. A negative token value would cause the return value
of recv_*_token() to become positive, which callers interpret as
literal data length, but no data pointer is set on this code path.

While this only causes the receiver to crash (which is process-isolated
and only affects the attacker's own connection), it's still undefined
behavior.

Reported-by: Will Sergeant <wlsergeant@gmail.com>
token.c

diff --git a/token.c b/token.c
index 91091be1f521f242de7f38d5329d592e7ac49032..773f14a2ce2810ca815cb094b982280468c79dff 100644 (file)
--- a/token.c
+++ b/token.c
@@ -590,8 +590,13 @@ static int32 recv_deflated_token(int f, char **data)
                        if (flag & TOKEN_REL) {
                                rx_token += flag & 0x3f;
                                flag >>= 6;
-                       } else
+                       } else {
                                rx_token = read_int(f);
+                               if (rx_token < 0) {
+                                       rprintf(FERROR, "invalid token number in compressed stream\n");
+                                       exit_cleanup(RERR_PROTOCOL);
+                               }
+                       }
                        if (flag & 1) {
                                rx_run = read_byte(f);
                                rx_run += read_byte(f) << 8;
@@ -834,8 +839,13 @@ static int32 recv_zstd_token(int f, char **data)
                        if (flag & TOKEN_REL) {
                                rx_token += flag & 0x3f;
                                flag >>= 6;
-                       } else
+                       } else {
                                rx_token = read_int(f);
+                               if (rx_token < 0) {
+                                       rprintf(FERROR, "invalid token number in compressed stream\n");
+                                       exit_cleanup(RERR_PROTOCOL);
+                               }
+                       }
                        if (flag & 1) {
                                rx_run = read_byte(f);
                                rx_run += read_byte(f) << 8;
@@ -998,8 +1008,13 @@ static int32 recv_compressed_token(int f, char **data)
                        if (flag & TOKEN_REL) {
                                rx_token += flag & 0x3f;
                                flag >>= 6;
-                       } else
+                       } else {
                                rx_token = read_int(f);
+                               if (rx_token < 0) {
+                                       rprintf(FERROR, "invalid token number in compressed stream\n");
+                                       exit_cleanup(RERR_PROTOCOL);
+                               }
+                       }
                        if (flag & 1) {
                                rx_run = read_byte(f);
                                rx_run += read_byte(f) << 8;