build: auto-detect the presence of the openat2() syscall#925
Conversation
|
This is for issue 924. |
|
Note that this doesn't fix |
|
It works for me. I just tried again after "make distclean".
This is with Ubuntu 18.04. Did you regenerate configure.sh after applying the patch? What does config.log have to say about detecting the presence of SYS_openat2? You should see something like this. And in config.log: |
|
But I see what you mean re: "make check". Let me take a look. ... That's because t_chmod_secure.c only has
instead of
Let me add that change to the pull request. |
|
BTW, |
|
My pull request is now updated to fix |
|
Unfortunately we also need runtime detection as android blocks the syscall for openat2 with seccomp, which signals the process on attempted openat2() calls, so we need runtime fallback. AOSP refused to fix. |
|
Having runtime detection makes sense. In part also because if built against newer kernel headers but run on a system with an older kernel, we'll want to make sure the functionality is actually available before using it. |
|
Compile-time detection of syscalls doesn't really make sense in the modern world of containers and seccomp, it makes far more sense to check this at runtime anyway. To be fair, modern glibc has wrappers for |
…dings, sans openat2) Squash-consolidates four campaign branches onto genuine master 3748c32, delivering the full hardening, fuzzing, and invariant-test net plus the discovered real-bug fixes. The openat2/R3 portability work is deliberately EXCLUDED here (superseded by upstream PR RsyncProject#925). Real-bug fixes (static-findings + fuzz-found): - receiver.c (R1): fix discard-path NULL deref. A block-match token arriving while fname==NULL / fd==-1 reached full_fname(NULL) (remote DoS); the mapbuf==NULL protocol error is now restricted to real-output transfers (fd != -1, fname non-NULL) and a block-match on the discard path is absorbed benignly as normal protocol. Locked in by fuzz/fuzz_recv_discard. - options.c (R2): zero-initialize *port_ptr so the later "!*port_ptr" reads can no longer observe an uninitialized caller value on the non-URL parse path. Residual hardening (harden-residuals): - hlink.c: lower-bound (ndx < flist->ndx_start) guards in match_gnums, check_prior, and finish_hard_link before indexing flist->files[]. - syscall.c: secure_mkstemp refuses templates with a ".." path component. - options.c: a daemon auto-refuses --copy-as. WS1/WS2/WS3 hardening net: - WS1 invariant + transport-equivalence tests (testsuite/equiv_fns.py plus content-fidelity, metadata-fidelity, link-dest-variants, link-dest-equiv, idempotence, delete-backup-invariants, transport-equiv-meta), wired via the new "check-equiv" Makefile.in target. Includes the D2 root/fakeroot skip and comment-reword net-correctness fixes. - WS2 libFuzzer harnesses under fuzz/: fuzz_io, fuzz_token, fuzz_deflated_token, fuzz_flist, fuzz_xattrs (live, linking the real recompiled flist.c/xattrs.c via RSYNC_FUZZ_* hooks), and fuzz_recv_discard; with stubs.c/globals.c, seed corpora, Makefile, and run-regression.sh (all six registered, ASan/UBSan). - WS3 CI: .github/workflows/{sanitizers-asan-ubsan,hardened-build, analysis-gcc-fanalyzer,analysis-scan-build,analysis-cppcheck,analysis-codeql} plus .github/ubsan-suppressions.txt and the --enable-hardened configure knob. - xattrs.c: zero-count UBSan source fixes (guard zero-length loops/memcpy). Excludes the openat2/R3 lane entirely: no configure-header-guard_test.py, no .github/workflows/portability.yml, no maint/check-openat2-portability.sh, and none of our openat2 AC_CHECK_HEADER fix. Upstream's openat2 scaffolding present in 3748c32 is left untouched. openat2/R3 superseded by upstream PR RsyncProject#925. Adversarial-review fixes folded in (CODE-REVIEW.md MINOR RsyncProject#1/RsyncProject#3, NIT RsyncProject#4): - test(equiv): equiv_fns.run_matrix asserts a per-scenario expected exit code instead of blanket-accepting 23, and idempotence_test _structural_fatal no longer drops only_in_* membership diffs (a dropped/spurious file on a round-trip leg is now fatal). Affected tests still pass; no divergence found. - fuzz: narrow LSan suppressions (fuzz/lsan-suppressions.txt naming only recv_file_entry / receive_xattr) wired into run-regression.sh for the flist/xattrs targets, so the intentional process-lifetime static caches no longer mask a genuine new leak; regression reports all targets clean. - fuzz: flist_for_ndx stub now aborts loudly instead of silently returning NULL, since no harness links the real implementation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
well, sort of ... when vendors like android use seccomp to block system calls (like they do for openat2) then from userspace point of view the ABI has changed .... sort of! |
|
I had a chat with @tridge and normally sandboxes use That's really painful -- and you can't detect it at build-time either! (Maybe Android should have some |
fcd22c4 to
b1d7780
Compare
Let configure detect if the openat2() syscall is supported by the kernel headers we are building against. Do not attempt to use openat2() if support is not present. Users can still disable using the openat2() syscall manually if so desired. Signed-off-by: Markus Mayer <mmayer@broadcom.com>
To prevent using openat2() in situations where it is not supported, use
#if defined(__linux__) && defined(HAVE_OPENAT2)
in t_chmod_secure.c, just like it was already being done in syscall.c.
Signed-off-by: Markus Mayer <mmayer@broadcom.com>
The openat2 secure resolver in syscall.c needs struct open_how and RESOLVE_BENEATH from <linux/openat2.h>, not only the SYS_openat2 syscall number. Some setups expose the syscall number via glibc without the kernel header present, so probing SYS_openat2 alone still left the build broken (RsyncProject#905). Exercise the header and struct in the configure check so HAVE_OPENAT2 is defined only when both are actually usable.
Android's seccomp sandbox traps openat2() with SECCOMP_RET_TRAP, which raises SIGSYS and kills the process instead of returning ENOSYS, so the secure resolver cannot simply try openat2() and inspect errno. Add openat2_usable() in a new android.c: it probes openat2() once behind a temporary SIGSYS handler and caches the result. Gate every SYS_openat2 call on openat2_usable(): in the resolver via an openat2_beneath() wrapper, and in t_chmod_secure's kernel probe directly, so a blocked openat2 reports ENOSYS and the caller falls back to the portable O_NOFOLLOW resolver. Only openat2 is gated -- a plain openat() (e.g. opening an operator-trusted absolute basedir) is left free. The probe body compiles only on Android -- __ANDROID__ is a Bionic target macro, so it is set for NDK cross-builds and native Termux alike and unset everywhere else, where openat2_usable() collapses to a constant 1. Link android.o into the secure-resolver test helpers too so their self-tests survive on Termux. Adapted from PR RsyncProject#909.
b1d7780 to
713c8d2
Compare
Let configure detect if the openat2() syscall is supported by the kernel headers we are building against. Do not attempt to use openat2() if support is not present.
Users can still disable using the openat2() syscall manually if so desired.