How my minimal, memory-safe Go rsync steers clear of vulnerabilities
How my minimal, memory-safe Go rsync steers clear of vulnerabilities
我的极简、内存安全 Go 版 rsync 如何规避漏洞
Back in January 2025, multiple different security researchers published a total of 6 security vulnerabilities in rsync, some of which allow arbitrary code execution and file leaks, so naturally I was wondering whether/how my gokrazy/rsync implementation was affected. Did implementing my own (compatible, but minimal) rsync in Go, a modern and memory-safe programming language, really rule out entire classes of security vulnerabilities? 2025 年 1 月,多位安全研究人员发布了总计 6 个 rsync 安全漏洞,其中一些漏洞允许任意代码执行和文件泄露。因此,我自然想知道我的 gokrazy/rsync 实现是否受到影响,以及受影响的程度。使用 Go 这种现代且内存安全的编程语言来实现我自己的(兼容但极简的)rsync,是否真的规避了整类安全漏洞?
This deep dive article was in the making since January 2025, but was delayed because we uncovered more unpublished vulnerabilities in the process! The “Security Vulnerabilities” section now covers all 12 vulnerabilities from the January 2025 batch and the May 2026 batch. If you are running (upstream, samba) rsync in production, upgrade to version 3.4.3 or newer. If you are running gokrazy/rsync in production, upgrade to version v0.3.3 or newer. 这篇深度分析文章自 2025 年 1 月起就开始撰写,但由于我们在过程中发现了更多未公开的漏洞,导致进度推迟!现在的“安全漏洞”部分涵盖了 2025 年 1 月批次和 2026 年 5 月批次总计 12 个漏洞。如果您在生产环境中使用(上游 samba)rsync,请升级到 3.4.3 或更新版本。如果您在生产环境中使用 gokrazy/rsync,请升级到 v0.3.3 或更新版本。
Feel free to skip over the nitty-gritty security issue details and jump directly to: 您可以随意跳过繁琐的安全问题细节,直接跳转至:
- The verdict on whether using Go has helped. (使用 Go 是否有帮助的结论)
- The verdict on whether a minimal re-implementation like gokrazy/rsync helps. (像 gokrazy/rsync 这样的极简重实现是否有帮助的结论)
- My comparison with OpenBSD’s openrsync (written in C). (我与 OpenBSD 的 openrsync(C 语言编写)的对比)
- Defense in depth mechanisms one can use on Linux. (在 Linux 上可以使用的纵深防御机制)
- The conclusion. (总结)
Context: My own rsync
背景:我自己的 rsync
For context, I blogged about rsync, how I use it, and how it works back in June 2022. See also all posts tagged “rsync”. The original motivation for writing my own rsync (back then only a server, today all directions are supported) was to provide the software packages of distri, my Linux distribution research project for fast package management, which I wanted to host on router7, my small home Linux+Go internet router, which in turn is built on gokrazy, my Go appliance platform. I am still running multiple gokrazy/rsync servers for this original purpose, and also many others! Having rsync available as a primitive (that you can link into your Go programs!) is really nice. 作为背景,我曾在 2022 年 6 月写过关于 rsync、我的使用方式及其工作原理的博客。另请参阅所有标记为“rsync”的文章。编写我自己的 rsync(当时仅支持服务端,今天已支持所有方向)的最初动机,是为了提供 distri 的软件包——这是我用于快速包管理的 Linux 发行版研究项目。我想将其托管在 router7 上,这是我小型家庭 Linux+Go 互联网路由器,而它又是基于我的 Go 设备平台 gokrazy 构建的。为了这个最初的目的,以及其他许多用途,我至今仍在运行多个 gokrazy/rsync 服务器!能将 rsync 作为一种原语(可以直接链接到你的 Go 程序中!)使用,感觉真的很棒。
Security Vulnerabilities
安全漏洞
This article covers the following security vulnerabilities: 本文涵盖了以下安全漏洞:
- CVE-2024-12084 to 12088 (original report)
- CVE-2024-12747 (discovered separately by Aleksei Gorban “loqpa”)
- CVE-2026-29518 (discovered by Damien Neil and myself! and independently by Nullx3D)
- CVE-2026-43617 to 43620
- CVE-2026-45232
The first batch of the vulnerabilities above was announced on the oss-security mailing list, but note that the original report has more detail compared to the oss-security summaries! The later vulnerabilities were announced via GitHub Security Advisories on the rsync project. 上述第一批漏洞是在 oss-security 邮件列表中公布的,但请注意,与 oss-security 的摘要相比,原始报告包含更多细节!后续的漏洞是通过 rsync 项目的 GitHub 安全公告发布的。
January 2025 batch
2025 年 1 月批次
CVE-2024-12084: Heap Buffer Overflow (9.8) CVE-2024-12084:堆缓冲区溢出 (9.8)
Summary: rsync performed insufficient validation: It read the (attacker-controlled) checksum length from the network and compared the length against MAX_DIGEST_LEN. However, rsync’s data structures always declared a 16 byte buffer: char sum2[SUM_LENGTH]. SUM_LENGTH is always 16 (bytes), which is sufficient to hold an MD4 or MD5 checksum. MAX_DIGEST_LEN used to be 16 (bytes), but can be larger when rsync is compiled with SHA256 or SHA512 checksum support. Hence, the bounds check was ineffective! An attacker could write out of bounds. This issue was introduced with commit ae16850 in September 2022, which added SHA256/SHA512 checksum support.
摘要:rsync 执行了不充分的验证:它从网络读取(攻击者可控的)校验和长度,并将该长度与 MAX_DIGEST_LEN 进行比较。然而,rsync 的数据结构总是声明一个 16 字节的缓冲区:char sum2[SUM_LENGTH]。SUM_LENGTH 始终为 16(字节),这足以容纳 MD4 或 MD5 校验和。MAX_DIGEST_LEN 过去是 16(字节),但当 rsync 使用 SHA256 或 SHA512 校验和支持编译时,它可能会更大。因此,边界检查失效了!攻击者可以进行越界写入。此问题是在 2022 年 9 月的提交 ae16850 中引入的,该提交增加了对 SHA256/SHA512 校验和的支持。
… (omitted technical code snippets for brevity) …
Can Go help prevent this? Go 能否帮助预防此类问题?
Yes: Missing or incorrect bounds checks will not result in a heap buffer overflow in Go! Instead, attempting to write out of bounds will result in a panic because the Go runtime performs bounds checks. 是的:在 Go 中,缺失或不正确的边界检查不会导致堆缓冲区溢出!相反,尝试越界写入会导致 panic,因为 Go 运行时会执行边界检查。
How does gokrazy/rsync fare? gokrazy/rsync 的表现如何?
gokrazy/rsync also had insufficient validation! Our issue was different, though: It wasn’t size confusion, we just were not doing any validation of the sum header at all — oop gokrazy/rsync 也存在验证不足的问题!不过我们的问题有所不同:这不是大小混淆,我们只是根本没有对校验和头部进行任何验证——哎呀。