From 324d6170820dca2ffe5be2e4fba88eb594345885 Mon Sep 17 00:00:00 2001 From: Zen Dodd Date: Sun, 12 Jul 2026 13:00:49 +1000 Subject: [PATCH 1/4] syscall: build without AT_SYMLINK_NOFOLLOW --- Makefile.in | 16 +++++++++++----- syscall.c | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Makefile.in b/Makefile.in index 5216fb2f7..ad024132e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -65,6 +65,8 @@ CHECK_SYMLINKS = testsuite/chown-fake_test.py testsuite/devices-fake_test.py \ # Objects for CHECK_PROGS to clean CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o t_chmod_secure.o t_secure_relpath.o trimslash.o wildtest.o +# Compile-only feature-shape checks. +CHECK_COMPILE_OBJS=syscall-no-at-fdcwd.o # note that the -I. is needed to handle config.h when using VPATH .c.o: @@ -72,6 +74,10 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o t_chmod_se $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@ @OBJ_RESTORE@ +syscall-no-at-fdcwd.o: syscall.c $(HEADERS) + $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) \ + -DRSYNC_TEST_NO_AT_FDCWD -c $(srcdir)/syscall.c -o $@ + # NOTE: consider running "packaging/smart-make" instead of "make" to auto-handle # any changes to configure.sh and the main Makefile prior to a "make all". all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_RRSYNC@ @MAKE_MAN@ @@ -300,7 +306,7 @@ rrsync.1: support/rrsync.1.md md-convert Makefile .PHONY: clean clean: cleantests - rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) @MAKE_RRSYNC@ \ + rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_COMPILE_OBJS) $(CHECK_SYMLINKS) @MAKE_RRSYNC@ \ git-version.h rounding rounding.h *.old rsync*.1 rsync*.5 @MAKE_RRSYNC_1@ \ *.html daemon-parm.h help-*.h default-*.h proto.h proto.h-tstamp rm -f *.gcno *.gcda lib/*.gcno lib/*.gcda zlib/*.gcno zlib/*.gcda popt/*.gcno popt/*.gcda @@ -378,18 +384,18 @@ COVERAGE_EXCLUDE = -e '(^|/)zlib/' -e '(^|/)popt/' \ # WITHOUT running it. Used by CI jobs that invoke runtests.py directly with # custom options (e.g. the version-mix workflow's --rsync-bin2/--expect-result). .PHONY: check-progs -check-progs: all $(CHECK_PROGS) $(CHECK_SYMLINKS) +check-progs: all $(CHECK_PROGS) $(CHECK_COMPILE_OBJS) $(CHECK_SYMLINKS) .PHONY: check -check: all $(CHECK_PROGS) $(CHECK_SYMLINKS) +check: all $(CHECK_PROGS) $(CHECK_COMPILE_OBJS) $(CHECK_SYMLINKS) $(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J) .PHONY: check29 -check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS) +check29: all $(CHECK_PROGS) $(CHECK_COMPILE_OBJS) $(CHECK_SYMLINKS) $(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J) --protocol=29 .PHONY: check30 -check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS) +check30: all $(CHECK_PROGS) $(CHECK_COMPILE_OBJS) $(CHECK_SYMLINKS) $(srcdir)/runtests.py --rsync-bin=`pwd`/rsync$(EXEEXT) -j $(CHECK_J) --protocol=30 # Whole-suite gcov coverage report (HTML, with branch + decision coverage). diff --git a/syscall.c b/syscall.c index 243f7f243..dfe9ed13d 100644 --- a/syscall.c +++ b/syscall.c @@ -22,6 +22,14 @@ #include "rsync.h" +/* Exercise the pre-*at() portability tier on modern build hosts. */ +#ifdef RSYNC_TEST_NO_AT_FDCWD +#undef AT_FDCWD +#undef AT_SYMLINK_NOFOLLOW +#undef HAVE_LINKAT +#undef HAVE_UTIMENSAT +#endif + #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H #include #endif @@ -426,7 +434,7 @@ int do_lchown(const char *path, uid_t owner, gid_t group) */ int do_lchown_at(const char *fname, uid_t owner, gid_t group) { -#ifdef AT_FDCWD +#if defined AT_FDCWD && defined AT_SYMLINK_NOFOLLOW extern int am_daemon, am_chrooted; char dirpath[MAXPATHLEN]; const char *bname; @@ -1181,6 +1189,7 @@ static int do_xstat_at(const char *path, STRUCT_STAT *st, int at_flags, int (*fa errno = e; return ret; #else + (void)at_flags; return fallback(path, st); #endif } @@ -1192,8 +1201,10 @@ int do_stat_at(const char *path, STRUCT_STAT *st) int do_lstat_at(const char *path, STRUCT_STAT *st) { -#ifdef SUPPORT_LINKS +#if defined SUPPORT_LINKS && defined AT_FDCWD && defined AT_SYMLINK_NOFOLLOW return do_xstat_at(path, st, AT_SYMLINK_NOFOLLOW, do_lstat); +#elif defined SUPPORT_LINKS + return do_lstat(path, st); #else return do_xstat_at(path, st, 0, do_stat); #endif @@ -2007,6 +2018,7 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo #endif // O_NOFOLLOW, O_DIRECTORY } +#if defined O_NOFOLLOW && defined O_DIRECTORY && defined AT_FDCWD /* Fill buf with len random bytes. Prefers /dev/urandom for cryptographic * quality; falls back to rand() if /dev/urandom cannot be opened or read * (e.g. inside a chroot or container without /dev populated). */ @@ -2027,6 +2039,7 @@ static void rand_bytes(unsigned char *buf, size_t len) buf[i] = (unsigned char)rand(); } } +#endif /* Secure version of mkstemp that prevents symlink attacks on parent directories. From 1f5976b86068a410976aa308240056a281c4d994 Mon Sep 17 00:00:00 2001 From: Zen Dodd Date: Sun, 12 Jul 2026 13:11:43 +1000 Subject: [PATCH 2/4] ci: fix no-AT_FDCWD compile check --- syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/syscall.c b/syscall.c index dfe9ed13d..c7f12d2c2 100644 --- a/syscall.c +++ b/syscall.c @@ -27,7 +27,9 @@ #undef AT_FDCWD #undef AT_SYMLINK_NOFOLLOW #undef HAVE_LINKAT +#undef HAVE_OPENAT2 #undef HAVE_UTIMENSAT +#undef O_RESOLVE_BENEATH #endif #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H From 053a6044dbbec91acf07946dcbe5e1821ec4c325 Mon Sep 17 00:00:00 2001 From: Zen Dodd Date: Sun, 12 Jul 2026 13:17:34 +1000 Subject: [PATCH 3/4] ci: restore default build target --- Makefile.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index ad024132e..ac14877b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -74,15 +74,15 @@ CHECK_COMPILE_OBJS=syscall-no-at-fdcwd.o $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@ @OBJ_RESTORE@ -syscall-no-at-fdcwd.o: syscall.c $(HEADERS) - $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) \ - -DRSYNC_TEST_NO_AT_FDCWD -c $(srcdir)/syscall.c -o $@ - # NOTE: consider running "packaging/smart-make" instead of "make" to auto-handle # any changes to configure.sh and the main Makefile prior to a "make all". all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_RRSYNC@ @MAKE_MAN@ .PHONY: all +syscall-no-at-fdcwd.o: syscall.c $(HEADERS) + $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) \ + -DRSYNC_TEST_NO_AT_FDCWD -c $(srcdir)/syscall.c -o $@ + .PHONY: install install: all -$(MKDIR_P) $(DESTDIR)$(bindir) From 905e34914879cac28b72e957e7d420f386acc44d Mon Sep 17 00:00:00 2001 From: Zen Dodd Date: Sun, 12 Jul 2026 13:31:54 +1000 Subject: [PATCH 4/4] testsuite: fix C23 bool compatibility --- wildtest.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wildtest.c b/wildtest.c index df87f9240..5867bb1cc 100644 --- a/wildtest.c +++ b/wildtest.c @@ -23,6 +23,7 @@ #include "lib/wildmatch.c" #include +#include #ifdef COMPARE_WITH_FNMATCH #include @@ -32,10 +33,6 @@ int fnmatch_errors = 0; int wildmatch_errors = 0; -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 202311L -typedef char bool; -#endif - int output_iterations = 0; int explode_mod = 0; int empties_mod = 0;