The default python3 on AlmaLinux 8 is 3.6, but runtests.py uses
subprocess.run(capture_output=...) and check_output(text=...) which
were introduced in 3.7. Install the python39 module stream and point
/usr/bin/python3 at it via alternatives so the existing shebang
resolves correctly.
Reproduced as: TypeError: __init__() got an unexpected keyword
argument 'capture_output' at runtests.py line 75.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The intent is to validate that future security fixes still build and
test cleanly on the oldest still-supported LTS releases of the two
mainstream Linux families, so backports can be developed against the
same CI surface as the trunk:
- ubuntu-22.04: oldest GitHub Actions runner image still available
(20.04 was retired in April 2025). Mirrors the existing
ubuntu-build.yml step list.
- almalinux-8: RHEL 8 rebuild, full support until 2029. Runs in an
almalinux:8 container on ubuntu-latest because GHA has no native
runner for the Fedora/RHEL family. Pulls libzstd/xxhash/lz4 dev
headers from PowerTools + EPEL; commonmark via pip for the man
page generator.
Both jobs follow the same paths-ignore convention as the other
workflows so a workflow-only change to one file won't fan out across
the whole CI matrix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Use unshare with user namespace UID mapping to run the
protected-regular test without real root privileges. Falls back
to skipping if unshare or uidmap is not available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The test correctly skips on Cygwin (which lacks RESOLVE_BENEATH), but
the workflow's RSYNC_EXPECT_SKIPPED list still treats any change in
the skipped set as a CI failure. Add the new test name so the
skipped/got comparison matches.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
secure_relative_open() has a kernel-enforced "stay below dirfd" path
on Linux 5.6+ (openat2 RESOLVE_BENEATH) and FreeBSD 13+ (openat
O_RESOLVE_BENEATH). On Solaris, OpenBSD, NetBSD, and Cygwin the code
falls back to the per-component O_NOFOLLOW walk, which by design
rejects every directory symlink in the path -- the very case this
test exercises. Mark the test skipped there rather than have it
fail with a known regression that's tracked separately.
macOS is intentionally not in the skip list: although it does not
have O_RESOLVE_BENEATH either, the test passes there in practice;
investigation of the underlying reason is left as follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FreeBSD and MacOS have O_RESOLVE_BENEATH as an openat() flag with the same
"must not escape dirfd" semantics as Linux's RESOLVE_BENEATH. The
kernel rejects ".." escapes, absolute symlinks, and symlinks whose
target lies outside dirfd, while still following symlinks that
resolve within it -- the same trade-off that fixes issue #715 on
Linux.
Add a parallel BSD path in secure_relative_open(), gated on
declared. Unlike Linux, BSD doesn't have the header/runtime split
where the symbol can exist without kernel support, so no runtime
fallback is needed: if the flag compiles in, the kernel honours it.
OpenBSD and NetBSD have no equivalent kernel primitive and continue
to use the existing per-component O_NOFOLLOW walk; issue #715
remains visible on those platforms (a userland resolver or
unveil(2)-based fence would be follow-up work).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The CVE fix in commit c35e283 made secure_relative_open() walk every
component of relpath with O_NOFOLLOW. That blocks every symlink in the
path, which is stricter than the threat model required: legitimate
directory symlinks within the destination tree (e.g. when using -K /
--copy-dirlinks) are also rejected, breaking delta transfers with
"failed verification -- update discarded". See issue #715.
On Linux 5.6+, openat2(RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS) gives
us exactly what we want: the kernel rejects any resolution that would
escape the starting directory (via "..", absolute paths, or symlinks
pointing outside dirfd) while still following symlinks that resolve
within it. /proc magic-links are blocked too.
Use openat2 first; fall back to the existing per-component O_NOFOLLOW
walk on ENOSYS (kernel < 5.6). The lexical "../" checks at the head
of the function are kept as defense in depth. The Linux gate is
plain #ifdef __linux__: the runtime ENOSYS fallback covers the only
case that actually matters (header present + old kernel), and any
Linux build environment without linux/openat2.h will fail with a
clear "no such file" error rather than silently disabling the
protection.
Verified manually that openat2(RESOLVE_BENEATH) blocks all four
escape patterns (absolute symlink, ../ symlink, lexical .., absolute
path) while allowing direct and within-tree symlinks. The new
testsuite/symlink-dirlink-basis.test (taken from PR #864 by Samuel
Henrique) exercises the issue #715 regression and passes; full
make check passes 47/47.
Test: testsuite/symlink-dirlink-basis.test (8 scenarios)
Fixes: https://github.com/RsyncProject/rsync/issues/715
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Solaris xls() function listed every entry in the file's xattr
directory, which on Solaris includes OS-managed SUNWattr_ro and
SUNWattr_rw pseudo-attributes. SUNWattr_rw embeds the file creation
time, so its bytes naturally differ between the source and destination
files, making the xattrs and xattrs-hlink tests fail with diffs that
have nothing to do with rsync.
Rsync's own listxattr wrapper already filters these out
(lib/sysxattrs.c), so the right fix is to filter them in the test
display too. Other platforms are unaffected because each has its own
xls() branch in the case statement.
With the test now actually passing on Solaris, drop the CI hack that
overwrote testsuite/xattrs.test with a skip stub.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the existing FreeBSD workflow for OpenBSD and NetBSD using
vmactions/openbsd-vm and vmactions/netbsd-vm so we get cross-BSD
coverage on push, PR, and the nightly schedule.
Also extend the FreeBSD and Solaris workflows to actually exercise the
test suite by running 'make check' after the build. The Linux, macOS,
and Cygwin jobs already did this.
The Solaris xattrs and xattrs-hlink tests are removed before 'make
check' because the Solaris SUNWattr_ro / SUNWattr_rw system attributes
leak into the test diff; that's a real rsync-on-Solaris issue to follow
up on, but skip the tests for now so the suite goes green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When invoked directly (rather than via 'make check'), runtests.py
previously left the user with a wall of confusing "not found" errors
from inside individual test scripts if the CHECK_PROGS helpers had not
been built. Detect this up front and point the user at the make
target that builds them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
localtime/localtime_r need /etc/localtime for timezone info.
After chroot this file is inaccessible, causing log timestamps
to fall back to UTC. Calling tzset() before chroot ensures the
timezone data is cached by glibc for subsequent calls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sorted() call reordered skipped test names alphabetically,
causing CI expected-skipped mismatches (e.g. acls,acls-default
instead of acls-default,acls). Sort by original test order instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add parallel test execution using concurrent.futures. With -j8 the
test suite completes in ~4s vs ~29s sequential (~7x speedup).
Also fix two issues that caused failures under parallel execution:
- rsync_ls_lR now prunes testtmp/ so parallel tests don't see each
other's temp files when scanning the source tree
- clean-fname-underflow.test now uses $scratchdir instead of /tmp
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite the test runner in Python with proper command-line options
including --valgrind which directs valgrind output to per-process
log files so it doesn't interfere with test output comparisons.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Glibc 2.43 added C23 const-preserving overloads to various string functions,
which change the return type depending on the constness of the argument(s).
Currently this leads to warnings from calls to strtok() or strchr().
Fix this by properly declaring the respective variable types.
Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
Change my_alloc() to use calloc instead of malloc so all fresh
allocations return zeroed memory. Also zero the expanded portion
in expand_item_list() after realloc, since it knows both old and
new sizes. This gives more predictable behaviour in case of bugs
where uninitialised or stale memory is accidentally accessed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
this fixes the count passed to the sort of the xattr list. This issue
was reported here:
https://www.openwall.com/lists/oss-security/2026/04/16/2
the bug is not exploitable due to the fork-per-connection design of
rsync, the attack is the equivalent of the user closing the socket
themselves.
The len field in the proxy v2 header was declared as signed char,
allowing a negative size to bypass the validation check and cause
a stack buffer overflow when passed to read_buf() as size_t.
This bug was reported by John Walker from ZeroPath, many thanks for
the clear report!
With the current code this bug does not represent a security issue as
it only results in the exit of the forked process that is specific to
the attached client, so it is equivalent to the client closing the
socket, so no CVE for this, but it is good to fix it to prevent a
future issue.
The bundled zlib 1.2.8 used K&R-style function definitions which are
rejected by clang 16+ as hard errors. Convert all 90 functions across
9 files to ANSI-style prototypes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The new simd-checksum test is skipped on platforms where SIMD
instructions are unavailable (macOS ARM, Cygwin). Add it to the
RSYNC_EXPECT_SKIPPED lists so CI doesn't fail on the mismatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The AVX2 get_checksum1_avx2_64() read mul_one before initializing it,
which is undefined behavior. Replace the cmpeq/abs trick with
_mm256_set1_epi8(1) to match the SSSE3 and SSE2 versions.
Add a TEST_SIMD_CHECKSUM1 test mode that verifies all SIMD paths
(SSE2, SSSE3, AVX2, and the full dispatch chain) produce identical
results to the C reference, across multiple buffer sizes with both
aligned and unaligned buffers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
The static buf1 pointer was only allocated when len > len1, but on
first call with len == 0, this condition is false (0 > 0), leaving
buf1 NULL when passed to memcpy().
Fixes#673
this was found by Calum Hutton from Rapid7. It is a real bug, but
analysis shows it can't be leverged into an exploit. Worth fixing
though.
Many thanks to Calum and Rapid7 for finding and reporting this
If poptGetContext returns NULL, perhaps due to OOM,
a NULL pointer is passed into poptReadDefaultConfig()
which in turns SEGVs when trying to dereference it.
This was found using https://github.com/sahlberg/malloc-fail-tester.git
$ ./test_malloc_failure.sh rsync -Pav crash crosh
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Int32x32To64 macro internally truncates the arguments to int32,
while time_t is 64-bit on most/all modern platforms.
Therefore, usage of this macro creates a Year 2038 bug.
This can happen when the tests are unable to `stat(2)` some files in
`/etc`, `/bin`, or `/`, due to Unix permissions or other sandboxing. We
still guard against serious errors, which use exit code 2.
In 2015, the attr/xattr.h header was fully removed from upstream attr.
In 2020, rsync started preferring the standard header, if it exists:
https://github.com/RsyncProject/rsync/pull/22
But the fix was incomplete. We still looked for the getxattr function in
-lattr, and used it if -lattr exists. This was the case even if the
system libc was sufficient to provide the needed functions. Result:
overlinking to -lattr, if it happened to be installed for any other
reason.
```
checking whether to support extended attributes... Using Linux xattrs
checking for getxattr in -lattr... yes
```
Instead, use a different autoconf macro that first checks if the
function is available for use without any libraries (e.g. it is in
libc).
Result:
```
checking whether to support extended attributes... Using Linux xattrs
checking for library containing getxattr... none required
```
Signed-off-by: Eli Schwartz <eschwartz@gentoo.org>