From 2def64a9fbcb125eeba8c2f1deeabe7a27f096d9 Mon Sep 17 00:00:00 2001 From: Ofer Chen Date: Fri, 22 May 2026 00:16:16 +0300 Subject: [PATCH] docs(security): SEC-1.i/.j helpers shipped; trim pending list, propose SEC-1.p SEC-1.i (PR #4690) and SEC-1.j (PR #4693) both shipped today, providing fchmodat/fchownat/utimensat and renameat sandbox helpers respectively. The prior "Mostly fixed" note still listed them as in flight; this update moves them into the Shipped list with PR references, trims the Remaining work list accordingly, and adds a forward-looking SEC-1.p Landlock LSM defense-in-depth proposal as the next layer. Status remains "Mostly fixed" pending receiver call-site wiring through DirSandbox (carrier-first staging) and SEC-1.p resolution. --- SECURITY.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 0f3c212bd..cd58e005a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -68,10 +68,10 @@ oc-rsync monitors upstream rsync CVEs to verify continued non-applicability. Rec | CVE-2024-12087 | Path traversal via --inc-recursive | Not vulnerable | Path sanitization | | CVE-2024-12088 | --safe-links bypass | Mitigated | Rust path handling | | CVE-2024-12747 | Symlink race condition | Mitigated | TOCTOU is OS-level | -| CVE-2026-29518 | TOCTOU symlink race in daemon receiver (`use chroot = no`) | **Mostly fixed** | Path-based syscalls have been migrated to `*at` variants routed through `DirSandbox` with `openat2(RESOLVE_BENEATH \| RESOLVE_NO_SYMLINKS)` runtime detection. SEC-1.a..h, .k..n have shipped; SEC-1.i/.j remain in flight (see SEC-1 progress note below). Umbrella tracking issue #2516. | +| CVE-2026-29518 | TOCTOU symlink race in daemon receiver (`use chroot = no`) | **Mostly fixed** | Path-based syscalls have been migrated to `*at` variants routed through `DirSandbox` with `openat2(RESOLVE_BENEATH \| RESOLVE_NO_SYMLINKS)` runtime detection. All `*at` helpers shipped (SEC-1.a..n); receiver wiring follow-up tracked separately (see SEC-1 progress note below). Umbrella tracking issue #2516. | | CVE-2026-43617 | Reverse-DNS lookup after daemon chroot causes hostname ACL bypass | Not vulnerable | `module_peer_hostname` runs in `module_access::listing` / `request` phases (`crates/daemon/src/daemon/sections/module_access/listing.rs:52`, `request.rs:269`) which complete before `chroot/setuid` in `transfer.rs:346-360`. | | CVE-2026-43618 | Integer overflow in compressed-token decoder causes memory disclosure | Mitigated | `crates/compress/src/zstd.rs:218,224` and `crates/compress/src/zlib/decoder.rs:61,67` use `saturating_add` for byte counters; explicit regression test `counting_writer_saturating_add_prevents_overflow` (`zlib/tests.rs:186-189`). Rust bounds-checking would panic on any post-overflow OOB index, not leak memory. | -| CVE-2026-43619 | Symlink races on chmod/lchown/utimes/rename/unlink/mkdir/symlink/mknod/link/rmdir/lstat | **Mostly fixed** | Same root cause as CVE-2026-29518. The `lstat` / `unlink` / `rmdir` / `mkdir` / `symlink` / `link` surfaces have been migrated to `fstatat` / `unlinkat` / `mkdirat` / `symlinkat` / `linkat` routed through `DirSandbox`; `chmod` / `lchown` / `utimes` (SEC-1.i) and `rename` (SEC-1.j) remain in flight (see SEC-1 progress note below). Umbrella tracking issue #2516. | +| CVE-2026-43619 | Symlink races on chmod/lchown/utimes/rename/unlink/mkdir/symlink/mknod/link/rmdir/lstat | **Mostly fixed** | Same root cause as CVE-2026-29518. All `*at` helpers shipped: `lstat` / `unlink` / `rmdir` / `mkdir` / `symlink` / `link` migrated to `fstatat` / `unlinkat` / `mkdirat` / `symlinkat` / `linkat`; `chmod` / `lchown` / `utimes` migrated to `fchmodat` / `fchownat` / `utimensat` (SEC-1.i, PR #4690); `rename` migrated to `renameat` (SEC-1.j, PR #4693). Receiver wiring follow-up tracked separately (see SEC-1 progress note below). Umbrella tracking issue #2516. | | CVE-2026-43620 | OOB read in `recv_files` via negative `parent_ndx` → client SIGSEGV | Not vulnerable | oc-rsync consumes the parent reference as `Option` and indexes into a bounds-checked `Vec` (`crates/protocol/src/flist/dir_tree.rs`). The validating entry point `DirectoryTree::try_add_directory` returns `DirTreeError::OutOfBoundsParent` on a malformed wire index; the unchecked `add_directory` aborts via Rust's bounds-check panic. Regression coverage: `try_add_directory_rejects_out_of_range_parent_idx`, `try_add_directory_rejects_boundary_off_by_one`, `add_directory_panics_safely_on_oob_parent_idx` in `crates/protocol/src/flist/dir_tree.rs`. SEC-4 closed. | | CVE-2026-45232 | Off-by-one stack write in HTTP CONNECT proxy response handler | Mitigated | `read_proxy_line()` in `crates/core/src/client/module_list/connect/proxy.rs` reads byte-by-byte into a heap `Vec` and explicitly caps the response line at `MAX_PROXY_LINE_BYTES = 1024` bytes, matching upstream's `establish_proxy_connection()` ceiling (socket.c:53). The C off-by-one stack-write is structurally impossible (bounds-checked `Vec::push`), and indefinite buffering is bounded by the explicit cap. Audit: SEC-2.a (PR #4609); upstream-parity alignment SEC-2.b. | @@ -88,7 +88,7 @@ rsync 3.4.3 (released 2026-05-20) is a major security release closing six CVEs a - **NULL-check on `localtime_r()` in `timestring()`** - oc-rsync uses `chrono`/`time` for timestamp formatting; out-of-range timestamps return `Err` rather than dereferencing a null pointer. Open follow-ups: -- **SEC-1** (TOCTOU on path-based daemon syscalls under `use_chroot=false`) - umbrella issue #2516, decomposed into SEC-1.a..o. Most mitigations have shipped (see SEC-1 progress note below); SEC-1.i and SEC-1.j remain in flight. Beta-blocker status lifts once SEC-1.i / SEC-1.j land and all receiver call sites are wired through `DirSandbox`. +- **SEC-1** (TOCTOU on path-based daemon syscalls under `use_chroot=false`) - umbrella issue #2516, decomposed into SEC-1.a..p. All `*at` helpers have shipped (SEC-1.a..n, including SEC-1.i in #4690 and SEC-1.j in #4693); the remaining work is receiver call-site wiring through `DirSandbox` and the proposed SEC-1.p Landlock LSM defense-in-depth layer (see SEC-1 progress note below). Beta-blocker status lifts once receiver wiring lands and SEC-1.p ships or is closed as N/A. - **SEC-2.b** (cosmetic: align proxy-line cap from 4096 to upstream's 1024) - SEC-2.a confirmed the structural mitigation is already in place via the 4096-byte cap at `connect/proxy.rs:337-372`; SEC-2.b is purely an upstream-parity tightening, not a security gap. - **SEC-3** (confirm hyphen-prefixed hostname rejection in SSH operand parse) - SEC-3.a audit in flight. - **SEC-4** (regression test for malformed `parent_node_idx` per CVE-2026-43620 mitigation) - closed. `DirectoryTree::try_add_directory` validates the wire-supplied parent index and returns `DirTreeError::OutOfBoundsParent`; three regression tests in `crates/protocol/src/flist/dir_tree.rs` pin down both the graceful-reject path and the worst-case controlled-panic path (no SIGSEGV). @@ -100,18 +100,20 @@ Shipped: - **SEC-1.f** (PR #4668): receiver `lstat` / `symlink_metadata` path resolves via `fstatat(AT_SYMLINK_NOFOLLOW)` routed through `DirSandbox`. - **SEC-1.g** (PR #4671): receiver `remove_file` / `remove_dir` path uses `unlinkat` routed through `DirSandbox`. - **SEC-1.h** (PR #4683): receiver `mkdir` / `symlink` / `hard_link` creation paths use `mkdirat` / `symlinkat` / `linkat` routed through `DirSandbox`. +- **SEC-1.i** (PR #4690): `fchmodat` / `fchownat` / `utimensat` sandbox helpers replace path-based `chmod` / `lchown` / `utimes`. +- **SEC-1.j** (PR #4693): `renameat` sandbox helper replaces path-based `rename`. - **SEC-1.k**: macOS verified - the `*at` syscall family is available and behaves consistently with the Linux migration. - **SEC-1.l**: Windows audited - NTFS handle-based APIs naturally sidestep the TOCTOU window, so Windows is not affected by either CVE. - **SEC-1.m** (PR #4675): comprehensive symlink-swap attack regression coverage against the daemon receiver. - **SEC-1.n** (PR #4678): interop regression coverage confirming legitimate symlinks still transfer correctly under the new `*at` paths. Remaining work: -- **SEC-1.i** - replace path-based `chmod` / `lchown` / `utimes` with `fchmodat` / `fchownat` / `utimensat`. In flight. -- **SEC-1.j** - replace path-based `rename` with `renameat`. In flight. -- **mknodat for device / FIFO nodes** - deferred; not on the daemon-reachable surface. -- **Receiver wiring for SEC-1.i helpers** - deferred to a follow-up; the carrier-first staging lands `*at` primitives ahead of full call-site migration. +- **mknodat for device / FIFO nodes** - DEFERRED (closure doc #4694; not on the daemon-reachable surface). +- **Receiver wiring for SEC-1.i helpers** - DEFERRED (carrier-first staging; metadata crate does not yet carry `DirSandbox`). +- **Receiver wiring for SEC-1.j deferred sites** - DEFERRED (`disk_commit`, `transfer_ops/response`, `local_copy/executor`; cross-thread carrier plumbing required). +- **SEC-1.p Landlock LSM defense-in-depth** - PROPOSED (audit in flight; Linux 5.13+, kernel-side enforcement that complements the `*at` helpers). -Target full-Fixed status: when SEC-1.i and SEC-1.j ship and all receiver call sites are wired through `DirSandbox`. +Target full-Fixed status: when receiver wiring for both SEC-1.i and SEC-1.j callers is complete AND (SEC-1.p Landlock layer ships OR is closed as N/A). CI integration: as of 2026-05-21 the interop job (`.github/workflows/_interop.yml`) runs upstream rsync's own `testsuite/*.test` corpus against oc-rsync as `$RSYNC`, pinned to upstream 3.4.3 by default. The known-failures roster lives at `tools/ci/upstream_testsuite_known_failures.conf`.