git: 558137064296 - main - net/rsync: Fix the handling of many xattrs on FreeBSD

From: Rodrigo Osorio <rodrigo_at_FreeBSD.org>
Date: Tue, 29 Jul 2025 18:50:11 UTC
The branch main has been updated by rodrigo:

URL: https://cgit.FreeBSD.org/ports/commit/?id=558137064296eac74a8b7d9b9a370a43e97bf329

commit 558137064296eac74a8b7d9b9a370a43e97bf329
Author:     Rodrigo Osorio <rodrigo@FreeBSD.org>
AuthorDate: 2025-07-12 10:43:16 +0000
Commit:     Rodrigo Osorio <rodrigo@FreeBSD.org>
CommitDate: 2025-07-29 18:43:49 +0000

    net/rsync: Fix the handling of many xattrs on FreeBSD
    
    Fix sys_llistxattr() for FreeBSD code to request a larger
    buffer to store the extended attributes list if the current
    one is too small.
    
    I also improve the attribute parsing by reducing to one the memmove
    calls when converting FreeBSD attribute list to the format used by
    Linux and extend the rsync unit tests for long xattrs lists.
    
    Changes where submitted to upstream as:
    https://github.com/RsyncProject/rsync/pull/781
    https://github.com/RsyncProject/rsync/pull/766
    
    PR:             286773
    Reported by:    Peter Eriksson <pen@lysator.liu.se>
    Obtained from:  Peter Eriksson <pen@lysator.liu.se>
    Reviewed by:    rodrigo
    Tested by:      rodrigo
    Event:          Berlin Hackaton 202507
    Relnotes:       yes
---
 net/rsync/Makefile                          |  2 +-
 net/rsync/files/patch-lib_sysxattrs.c       | 42 ++++++++++++++++++
 net/rsync/files/patch-testsuite_xattrs.test | 67 +++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/net/rsync/Makefile b/net/rsync/Makefile
index 5977ac517199..e495116560b8 100644
--- a/net/rsync/Makefile
+++ b/net/rsync/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=	rsync
 DISTVERSION=	3.4.1
-PORTREVISION=	2
+PORTREVISION=	3
 CATEGORIES=	net
 MASTER_SITES=	https://www.mirrorservice.org/sites/rsync.samba.org/src/ \
 		http://rsync.mirror.garr.it/src/ \
diff --git a/net/rsync/files/patch-lib_sysxattrs.c b/net/rsync/files/patch-lib_sysxattrs.c
new file mode 100644
index 000000000000..16a307a83ad6
--- /dev/null
+++ b/net/rsync/files/patch-lib_sysxattrs.c
@@ -0,0 +1,42 @@
+--- a/lib/sysxattrs.c.orig	2022-01-16 01:21:01.000000000 +0000
++++ b/lib/sysxattrs.c	2025-07-28 12:05:43.501532000 +0000
+@@ -126,22 +126,29 @@
+ 	unsigned char keylen;
+ 	ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
+ 
+-	if (len <= 0 || (size_t)len > size)
++	if (len <= 0 || size == 0)
+ 		return len;
+ 
++	if ((size_t)len == size) {
++		/* extattr_list_link fills a buffer with a list of file attributes.
++		 * If the buffer size is too small the content is truncated and
++		 * extattr_list_link returns the number of written bytes and no
++		 * error is raised. If size == len assumes the buffer was too small
++		 * and behave like Linux requesting a larger buffer. */
++		errno = ERANGE;
++		return -1;
++	}
++
+ 	/* FreeBSD puts a single-byte length before each string, with no '\0'
+ 	 * terminator.  We need to change this into a series of null-terminted
+ 	 * strings.  Since the size is the same, we can simply transform the
+ 	 * output in place. */
+-	for (off = 0; off < len; off += keylen + 1) {
+-		keylen = ((unsigned char*)list)[off];
+-		if (off + keylen >= len) {
+-			/* Should be impossible, but kernel bugs happen! */
+-			errno = EINVAL;
+-			return -1;
+-		}
+-		memmove(list+off, list+off+1, keylen);
+-		list[off+keylen] = '\0';
++	keylen = (unsigned char)list[0];
++	memmove(list, list+1, len-1);
++	list[len-1] = '\0';
++	for (off = keylen; off < (len - 1); off += (keylen + 1)) {
++		keylen = (unsigned char)list[off];
++		list[off] = '\0';
+ 	}
+ 
+ 	return len;
diff --git a/net/rsync/files/patch-testsuite_xattrs.test b/net/rsync/files/patch-testsuite_xattrs.test
new file mode 100644
index 000000000000..95a1a285d96b
--- /dev/null
+++ b/net/rsync/files/patch-testsuite_xattrs.test
@@ -0,0 +1,67 @@
+--- a/testsuite/xattrs.test.orig	2022-10-20 16:09:26.000000000 +0000
++++ b/testsuite/xattrs.test	2025-06-29 07:49:45.880992000 +0000
+@@ -10,7 +10,14 @@
+ 
+ $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync is configured without xattr support"
+ 
++CYGWIN=0
++
+ case "$HOST_OS" in
++cygwin*)
++    CYGWIN=1
++esac
++
++case "$HOST_OS" in
+ darwin*)
+     xset() {
+ 	xnam="$1"
+@@ -80,6 +87,9 @@
+ echo deep >"$fromdir/foo/file3"
+ echo normal >"$fromdir/file4"
+ echo deeper >"$fromdir/foo/bar/file5"
++if [ $CYGWIN -eq 0 ]; then
++    echo longxattrname >"$fromdir/file7"
++fi
+ 
+ makepath "$chkdir/foo"
+ echo wow >"$chkdir/file1"
+@@ -87,6 +97,10 @@
+ 
+ dirs='foo foo/bar'
+ files='file0 file1 file2 foo/file3 file4 foo/bar/file5'
++if [ $CYGWIN -eq 0 ]
++then
++        files="$files file7"
++fi
+ 
+ uid_gid=`"$TOOLDIR/tls" "$fromdir/foo" | sed 's/^.* \([0-9][0-9]*\)\.\([0-9][0-9]*\) .*/\1:\2/'`
+ 
+@@ -125,6 +139,16 @@
+ xset user.foo 'old foo' "$chkdir/foo/file3"
+ xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
+ 
++if [ $CYGWIN -eq 0 ] ; then
++# Generate xattr names
++SEQ=`seq 1 200`
++xset user."`printf -- 'A%0.s' $SEQ`" 'first xattr' file7
++xset user."`printf -- 'B%0.s' $SEQ`" 'second xattr' file7
++xset user."`printf -- 'C%0.s' $SEQ`" 'third xattr' file7
++xset user."`printf -- 'D%0.s' $SEQ`" 'another xattr' file7
++xset user."`printf -- 'E%0.s' $SEQ`" 'final xattr' file7
++fi
++
+ case $0 in
+ *hlink*)
+     ln foo/bar/file5 foo/bar/file6 || test_skipped "Can't create hardlink"
+@@ -234,6 +258,11 @@
+ 
+ cd "$todir"
+ xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" -
++
++cd "$fromdir"
++rm -rf "$todir"
++mkfifo fifo1
++checktee "$RSYNC -avX --specials  $XFILT $dashH --super . '$chkdir/'" "$fromdir" "$chkdir"
+ 
+ # The script would have aborted on error, so getting here means we've won.
+ exit 0