diff --git a/Makefile.in b/Makefile.in index 5216fb2f7..ac14877b8 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: @@ -77,6 +79,10 @@ CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o t_chmod_se 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) @@ -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..c7f12d2c2 100644 --- a/syscall.c +++ b/syscall.c @@ -22,6 +22,16 @@ #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_OPENAT2 +#undef HAVE_UTIMENSAT +#undef O_RESOLVE_BENEATH +#endif + #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H #include #endif @@ -426,7 +436,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 +1191,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 +1203,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 +2020,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 +2041,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. 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;