- Security update,CVE-2024-12747, bsc#1235475 race condition in handling symbolic links

* Added rsync-CVE-2024-12747.patch

- Security update, fix multiple vulnerabilities:
  * CVE-2024-12084, bsc#1234100 - Heap Buffer Overflow in Checksum Parsing
  * CVE-2024-12085, bsc#1234101 - Info Leak via uninitialized Stack contents defeats ASLR
  * CVE-2024-12086, bsc#1234102 - Server leaks arbitrary client files
  * CVE-2024-12087, bsc#1234103 - Server can make client write files outside of destination directory using symbolic links
  * CVE-2024-12088, bsc#1234104 - --safe-links Bypass
  * Added rsync-CVE-2024-12084-overflow-01.patch
  * Added rsync-CVE-2024-12084-overflow-02.patch
  * Added rsync-CVE-2024-12085.patch
  * Added rsync-CVE-2024-12086_01.patch
  * Added rsync-CVE-2024-12086_02.patch
  * Added rsync-CVE-2024-12086_03.patch
  * Added rsync-CVE-2024-12086_04.patch
  * Added rsync-CVE-2024-12087_01.patch
  * Added rsync-CVE-2024-12087_02.patch
  * Added rsync-CVE-2024-12088.patch

OBS-URL: https://build.opensuse.org/package/show/network/rsync?expand=0&rev=129
This commit is contained in:
Angel Yankov 2025-01-15 08:07:45 +00:00 committed by Git OBS Bridge
commit 04926b0b74
33 changed files with 2925 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.osc

11
logrotate.rsync Normal file
View File

@ -0,0 +1,11 @@
/var/log/rsyncd.log {
compress
dateext
maxage 365
rotate 99
size=+1024k
notifempty
missingok
copytruncate
}

BIN
rsync-3.3.0.tar.gz (Stored with Git LFS) Normal file

Binary file not shown.

6
rsync-3.3.0.tar.gz.asc Normal file
View File

@ -0,0 +1,6 @@
-----BEGIN PGP SIGNATURE-----
iF0EABECAB0WIQQASMiwJtTJbw5YnC9shZ+xS5aoxQUCZhF6vQAKCRBshZ+xS5ao
xZ6kAKDZkE3C9w/cu8o3/Ic5KNycbcTw8gCdH/pdNo6kSGF3qLelFI6uK5Q4jdA=
=vJGJ
-----END PGP SIGNATURE-----

View File

@ -0,0 +1,152 @@
From 0902b52f6687b1f7952422080d50b93108742e53 Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Tue, 29 Oct 2024 22:55:29 -0700
Subject: [PATCH 1/2] Some checksum buffer fixes.
- Put sum2_array into sum_struct to hold an array of sum2 checksums
that are each xfer_sum_len bytes.
- Remove sum2 buf from sum_buf.
- Add macro sum2_at() to access each sum2 array element.
- Throw an error if a sums header has an s2length larger than
xfer_sum_len.
---
io.c | 3 ++-
match.c | 8 ++++----
rsync.c | 5 ++++-
rsync.h | 4 +++-
sender.c | 4 +++-
5 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/io.c b/io.c
index a99ac0ec..bb60eeca 100644
--- a/io.c
+++ b/io.c
@@ -55,6 +55,7 @@ extern int read_batch;
extern int compat_flags;
extern int protect_args;
extern int checksum_seed;
+extern int xfer_sum_len;
extern int daemon_connection;
extern int protocol_version;
extern int remove_source_files;
@@ -1977,7 +1978,7 @@ void read_sum_head(int f, struct sum_struct *sum)
exit_cleanup(RERR_PROTOCOL);
}
sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f);
- if (sum->s2length < 0 || sum->s2length > MAX_DIGEST_LEN) {
+ if (sum->s2length < 0 || sum->s2length > xfer_sum_len) {
rprintf(FERROR, "Invalid checksum length %d [%s]\n",
sum->s2length, who_am_i());
exit_cleanup(RERR_PROTOCOL);
diff --git a/match.c b/match.c
index cdb30a15..36e78ed2 100644
--- a/match.c
+++ b/match.c
@@ -232,7 +232,7 @@ static void hash_search(int f,struct sum_struct *s,
done_csum2 = 1;
}
- if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) {
+ if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0) {
false_alarms++;
continue;
}
@@ -252,7 +252,7 @@ static void hash_search(int f,struct sum_struct *s,
if (i != aligned_i) {
if (sum != s->sums[aligned_i].sum1
|| l != s->sums[aligned_i].len
- || memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0)
+ || memcmp(sum2, sum2_at(s, aligned_i), s->s2length) != 0)
goto check_want_i;
i = aligned_i;
}
@@ -271,7 +271,7 @@ static void hash_search(int f,struct sum_struct *s,
if (sum != s->sums[i].sum1)
goto check_want_i;
get_checksum2((char *)map, l, sum2);
- if (memcmp(sum2, s->sums[i].sum2, s->s2length) != 0)
+ if (memcmp(sum2, sum2_at(s, i), s->s2length) != 0)
goto check_want_i;
/* OK, we have a re-alignment match. Bump the offset
* forward to the new match point. */
@@ -290,7 +290,7 @@ static void hash_search(int f,struct sum_struct *s,
&& (!updating_basis_file || s->sums[want_i].offset >= offset
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
&& sum == s->sums[want_i].sum1
- && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
+ && memcmp(sum2, sum2_at(s, want_i), s->s2length) == 0) {
/* we've found an adjacent match - the RLL coder
* will be happy */
i = want_i;
diff --git a/rsync.c b/rsync.c
index cd288f57..b130aba5 100644
--- a/rsync.c
+++ b/rsync.c
@@ -437,7 +437,10 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, cha
*/
void free_sums(struct sum_struct *s)
{
- if (s->sums) free(s->sums);
+ if (s->sums) {
+ free(s->sums);
+ free(s->sum2_array);
+ }
free(s);
}
diff --git a/rsync.h b/rsync.h
index d3709fe0..8ddbe702 100644
--- a/rsync.h
+++ b/rsync.h
@@ -958,12 +958,12 @@ struct sum_buf {
uint32 sum1; /**< simple checksum */
int32 chain; /**< next hash-table collision */
short flags; /**< flag bits */
- char sum2[SUM_LENGTH]; /**< checksum */
};
struct sum_struct {
OFF_T flength; /**< total file length */
struct sum_buf *sums; /**< points to info for each chunk */
+ char *sum2_array; /**< checksums of length xfer_sum_len */
int32 count; /**< how many chunks */
int32 blength; /**< block_length */
int32 remainder; /**< flength % block_length */
@@ -982,6 +982,8 @@ struct map_struct {
int status; /* first errno from read errors */
};
+#define sum2_at(s, i) ((s)->sum2_array + ((OFF_T)(i) * xfer_sum_len))
+
#define NAME_IS_FILE (0) /* filter name as a file */
#define NAME_IS_DIR (1<<0) /* filter name as a dir */
#define NAME_IS_XATTR (1<<2) /* filter name as an xattr */
diff --git a/sender.c b/sender.c
index 3d4f052e..ab205341 100644
--- a/sender.c
+++ b/sender.c
@@ -31,6 +31,7 @@ extern int log_before_transfer;
extern int stdout_format_has_i;
extern int logfile_format_has_i;
extern int want_xattr_optim;
+extern int xfer_sum_len;
extern int csum_length;
extern int append_mode;
extern int copy_links;
@@ -94,10 +95,11 @@ static struct sum_struct *receive_sums(int f)
return(s);
s->sums = new_array(struct sum_buf, s->count);
+ s->sum2_array = new_array(char, s->count * xfer_sum_len);
for (i = 0; i < s->count; i++) {
s->sums[i].sum1 = read_int(f);
- read_buf(f, s->sums[i].sum2, s->s2length);
+ read_buf(f, sum2_at(s, i), s->s2length);
s->sums[i].offset = offset;
s->sums[i].flags = 0;
--
2.34.1

View File

@ -0,0 +1,40 @@
From 42e2b56c4ede3ab164f9a5c6dae02aa84606a6c1 Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Tue, 5 Nov 2024 11:01:03 -0800
Subject: [PATCH 2/2] Another cast when multiplying integers.
---
rsync.h | 2 +-
sender.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/rsync.h b/rsync.h
index 8ddbe702..0f9e277f 100644
--- a/rsync.h
+++ b/rsync.h
@@ -982,7 +982,7 @@ struct map_struct {
int status; /* first errno from read errors */
};
-#define sum2_at(s, i) ((s)->sum2_array + ((OFF_T)(i) * xfer_sum_len))
+#define sum2_at(s, i) ((s)->sum2_array + ((size_t)(i) * xfer_sum_len))
#define NAME_IS_FILE (0) /* filter name as a file */
#define NAME_IS_DIR (1<<0) /* filter name as a dir */
diff --git a/sender.c b/sender.c
index ab205341..2bbff2fa 100644
--- a/sender.c
+++ b/sender.c
@@ -95,7 +95,7 @@ static struct sum_struct *receive_sums(int f)
return(s);
s->sums = new_array(struct sum_buf, s->count);
- s->sum2_array = new_array(char, s->count * xfer_sum_len);
+ s->sum2_array = new_array(char, (size_t)s->count * xfer_sum_len);
for (i = 0; i < s->count; i++) {
s->sums[i].sum1 = read_int(f);
--
2.34.1

View File

@ -0,0 +1,28 @@
From cf620065502f065d4ea44f5df4f81295a738aa21 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Thu, 14 Nov 2024 09:57:08 +1100
Subject: [PATCH] prevent information leak off the stack
prevent leak of uninitialised stack data in hash_search
---
match.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/match.c b/match.c
index 36e78ed2..dfd6af2c 100644
--- a/match.c
+++ b/match.c
@@ -147,6 +147,9 @@ static void hash_search(int f,struct sum_struct *s,
int more;
schar *map;
+ // prevent possible memory leaks
+ memset(sum2, 0, sizeof sum2);
+
/* want_i is used to encourage adjacent matches, allowing the RLL
* coding of the output to work more efficiently. */
want_i = 0;
--
2.34.1

View File

@ -0,0 +1,38 @@
From 3feb8669d875d03c9ceb82e208ef40ddda8eb908 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Sat, 23 Nov 2024 11:08:03 +1100
Subject: [PATCH 1/4] refuse fuzzy options when fuzzy not selected
this prevents a malicious server providing a file to compare to when
the user has not given the fuzzy option
---
receiver.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/receiver.c b/receiver.c
index 6b4b369e..2d7f6033 100644
--- a/receiver.c
+++ b/receiver.c
@@ -66,6 +66,7 @@ extern char sender_file_sum[MAX_DIGEST_LEN];
extern struct file_list *cur_flist, *first_flist, *dir_flist;
extern filter_rule_list daemon_filter_list;
extern OFF_T preallocated_len;
+extern int fuzzy_basis;
extern struct name_num_item *xfer_sum_nni;
extern int xfer_sum_len;
@@ -716,6 +717,10 @@ int recv_files(int f_in, int f_out, char *local_name)
fnamecmp = get_backup_name(fname);
break;
case FNAMECMP_FUZZY:
+ if (fuzzy_basis == 0) {
+ rprintf(FERROR_XFER, "rsync: refusing malicious fuzzy operation for %s\n", xname);
+ exit_cleanup(RERR_PROTOCOL);
+ }
if (file->dirname) {
pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname);
fnamecmp = fnamecmpbuf;
--
2.34.1

View File

@ -0,0 +1,104 @@
From 33385aefe4773e7a3982d41995681eb079c92d12 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Sat, 23 Nov 2024 12:26:10 +1100
Subject: [PATCH 2/4] added secure_relative_open()
this is an open that enforces no symlink following for all path
components in a relative path
---
syscall.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/syscall.c b/syscall.c
index d92074aa..a4b7f542 100644
--- a/syscall.c
+++ b/syscall.c
@@ -33,6 +33,8 @@
#include <sys/syscall.h>
#endif
+#include "ifuncs.h"
+
extern int dry_run;
extern int am_root;
extern int am_sender;
@@ -712,3 +714,75 @@ int do_open_nofollow(const char *pathname, int flags)
return fd;
}
+
+/*
+ open a file relative to a base directory. The basedir can be NULL,
+ in which case the current working directory is used. The relpath
+ must be a relative path, and the relpath must not contain any
+ elements in the path which follow symlinks (ie. like O_NOFOLLOW, but
+ applies to all path components, not just the last component)
+*/
+int secure_relative_open(const char *basedir, const char *relpath, int flags, mode_t mode)
+{
+ if (!relpath || relpath[0] == '/') {
+ // must be a relative path
+ errno = EINVAL;
+ return -1;
+ }
+
+#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY)
+ // really old system, all we can do is live with the risks
+ if (!basedir) {
+ return open(relpath, flags, mode);
+ }
+ char fullpath[MAXPATHLEN];
+ pathjoin(fullpath, sizeof fullpath, basedir, relpath);
+ return open(fullpath, flags, mode);
+#else
+ int dirfd = AT_FDCWD;
+ if (basedir != NULL) {
+ dirfd = openat(AT_FDCWD, basedir, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ return -1;
+ }
+ }
+ int retfd = -1;
+
+ char *path_copy = my_strdup(relpath, __FILE__, __LINE__);
+ if (!path_copy) {
+ return -1;
+ }
+
+ for (const char *part = strtok(path_copy, "/");
+ part != NULL;
+ part = strtok(NULL, "/"))
+ {
+ int next_fd = openat(dirfd, part, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
+ if (next_fd == -1 && errno == ENOTDIR) {
+ if (strtok(NULL, "/") != NULL) {
+ // this is not the last component of the path
+ errno = ELOOP;
+ goto cleanup;
+ }
+ // this could be the last component of the path, try as a file
+ retfd = openat(dirfd, part, flags | O_NOFOLLOW, mode);
+ goto cleanup;
+ }
+ if (next_fd == -1) {
+ goto cleanup;
+ }
+ if (dirfd != AT_FDCWD) close(dirfd);
+ dirfd = next_fd;
+ }
+
+ // the path must be a directory
+ errno = EINVAL;
+
+cleanup:
+ free(path_copy);
+ if (dirfd != AT_FDCWD) {
+ close(dirfd);
+ }
+ return retfd;
+#endif // O_NOFOLLOW, O_DIRECTORY
+}
--
2.34.1

View File

@ -0,0 +1,104 @@
From e59ef9939d3f0ccc8f9bab51442989a81be0c914 Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Sat, 23 Nov 2024 12:28:13 +1100
Subject: [PATCH 3/4] receiver: use secure_relative_open() for basis file
this prevents attacks where the basis file is manipulated by a
malicious sender to gain information about files outside the
destination tree
---
receiver.c | 42 ++++++++++++++++++++++++++----------------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/receiver.c b/receiver.c
index 2d7f6033..8031b8f4 100644
--- a/receiver.c
+++ b/receiver.c
@@ -552,6 +552,8 @@ int recv_files(int f_in, int f_out, char *local_name)
progress_init();
while (1) {
+ const char *basedir = NULL;
+
cleanup_disable();
/* This call also sets cur_flist. */
@@ -722,27 +724,29 @@ int recv_files(int f_in, int f_out, char *local_name)
exit_cleanup(RERR_PROTOCOL);
}
if (file->dirname) {
- pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname);
- fnamecmp = fnamecmpbuf;
- } else
- fnamecmp = xname;
+ basedir = file->dirname;
+ }
+ fnamecmp = xname;
break;
default:
if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) {
fnamecmp_type -= FNAMECMP_FUZZY + 1;
if (file->dirname) {
- stringjoin(fnamecmpbuf, sizeof fnamecmpbuf,
- basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL);
- } else
- pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname);
+ pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], file->dirname);
+ basedir = fnamecmpbuf;
+ } else {
+ basedir = basis_dir[fnamecmp_type];
+ }
+ fnamecmp = xname;
} else if (fnamecmp_type >= basis_dir_cnt) {
rprintf(FERROR,
"invalid basis_dir index: %d.\n",
fnamecmp_type);
exit_cleanup(RERR_PROTOCOL);
- } else
- pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname);
- fnamecmp = fnamecmpbuf;
+ } else {
+ basedir = basis_dir[fnamecmp_type];
+ fnamecmp = fname;
+ }
break;
}
if (!fnamecmp || (daemon_filter_list.head
@@ -765,7 +769,7 @@ int recv_files(int f_in, int f_out, char *local_name)
}
/* open the file */
- fd1 = do_open(fnamecmp, O_RDONLY, 0);
+ fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0);
if (fd1 == -1 && protocol_version < 29) {
if (fnamecmp != fname) {
@@ -776,14 +780,20 @@ int recv_files(int f_in, int f_out, char *local_name)
if (fd1 == -1 && basis_dir[0]) {
/* pre-29 allowed only one alternate basis */
- pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
- basis_dir[0], fname);
- fnamecmp = fnamecmpbuf;
+ basedir = basis_dir[0];
+ fnamecmp = fname;
fnamecmp_type = FNAMECMP_BASIS_DIR_LOW;
- fd1 = do_open(fnamecmp, O_RDONLY, 0);
+ fd1 = secure_relative_open(basedir, fnamecmp, O_RDONLY, 0);
}
}
+ if (basedir) {
+ // for the following code we need the full
+ // path name as a single string
+ pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basedir, fnamecmp);
+ fnamecmp = fnamecmpbuf;
+ }
+
one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR;
updating_basis_or_equiv = one_inplace
|| (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP));
--
2.34.1

View File

@ -0,0 +1,38 @@
From c78e53edb802d04f7e4e070fe8314f2544749e7a Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Tue, 26 Nov 2024 09:16:31 +1100
Subject: [PATCH 4/4] disallow ../ elements in relpath for secure_relative_open
---
syscall.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/syscall.c b/syscall.c
index a4b7f542..47c5ea57 100644
--- a/syscall.c
+++ b/syscall.c
@@ -721,6 +721,8 @@ int do_open_nofollow(const char *pathname, int flags)
must be a relative path, and the relpath must not contain any
elements in the path which follow symlinks (ie. like O_NOFOLLOW, but
applies to all path components, not just the last component)
+
+ The relpath must also not contain any ../ elements in the path
*/
int secure_relative_open(const char *basedir, const char *relpath, int flags, mode_t mode)
{
@@ -729,6 +731,11 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo
errno = EINVAL;
return -1;
}
+ if (strncmp(relpath, "../", 3) == 0 || strstr(relpath, "/../")) {
+ // no ../ elements allowed in the relpath
+ errno = EINVAL;
+ return -1;
+ }
#if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY)
// really old system, all we can do is live with the risks
--
2.34.1

View File

@ -0,0 +1,46 @@
From 0ebc19ee486a8e928a68d8f98d07d40f176770aa Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Thu, 14 Nov 2024 15:46:50 -0800
Subject: [PATCH 1/2] Refuse a duplicate dirlist.
---
flist.c | 9 +++++++++
rsync.h | 1 +
2 files changed, 10 insertions(+)
diff --git a/flist.c b/flist.c
index 464d556e..847b1054 100644
--- a/flist.c
+++ b/flist.c
@@ -2584,6 +2584,15 @@ struct file_list *recv_file_list(int f, int dir_ndx)
init_hard_links();
#endif
+ if (inc_recurse && dir_ndx >= 0) {
+ struct file_struct *file = dir_flist->files[dir_ndx];
+ if (file->flags & FLAG_GOT_DIR_FLIST) {
+ rprintf(FERROR_XFER, "rsync: refusing malicious duplicate flist for dir %d\n", dir_ndx);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ file->flags |= FLAG_GOT_DIR_FLIST;
+ }
+
flist = flist_new(0, "recv_file_list");
flist_expand(flist, FLIST_START_LARGE);
diff --git a/rsync.h b/rsync.h
index 0f9e277f..b9a7101a 100644
--- a/rsync.h
+++ b/rsync.h
@@ -84,6 +84,7 @@
#define FLAG_DUPLICATE (1<<4) /* sender */
#define FLAG_MISSING_DIR (1<<4) /* generator */
#define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */
+#define FLAG_GOT_DIR_FLIST (1<<5)/* sender/receiver/generator - dir_flist only */
#define FLAG_HLINK_FIRST (1<<6) /* receiver/generator (w/FLAG_HLINKED) */
#define FLAG_IMPLIED_DIR (1<<6) /* sender/receiver/generator (dirs only) */
#define FLAG_HLINK_LAST (1<<7) /* receiver/generator */
--
2.34.1

View File

@ -0,0 +1,28 @@
From b3e16be18d582dac1513c0a932d146b36e867b1b Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Tue, 26 Nov 2024 16:12:45 +1100
Subject: [PATCH 2/2] range check dir_ndx before use
---
flist.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/flist.c b/flist.c
index 847b1054..087f9da6 100644
--- a/flist.c
+++ b/flist.c
@@ -2585,6 +2585,10 @@ struct file_list *recv_file_list(int f, int dir_ndx)
#endif
if (inc_recurse && dir_ndx >= 0) {
+ if (dir_ndx >= dir_flist->used) {
+ rprintf(FERROR_XFER, "rsync: refusing invalid dir_ndx %u >= %u\n", dir_ndx, dir_flist->used);
+ exit_cleanup(RERR_PROTOCOL);
+ }
struct file_struct *file = dir_flist->files[dir_ndx];
if (file->flags & FLAG_GOT_DIR_FLIST) {
rprintf(FERROR_XFER, "rsync: refusing malicious duplicate flist for dir %d\n", dir_ndx);
--
2.34.1

137
rsync-CVE-2024-12088.patch Normal file
View File

@ -0,0 +1,137 @@
From 535f8f816539ba681ef0f12015d2cb587ae61b6d Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Sat, 23 Nov 2024 15:15:53 +1100
Subject: [PATCH] make --safe-links stricter
when --safe-links is used also reject links where a '../' component is
included in the destination as other than the leading part of the
filename
---
testsuite/safe-links.test | 55 ++++++++++++++++++++++++++++++++++++
testsuite/unsafe-byname.test | 2 +-
util1.c | 26 ++++++++++++++++-
3 files changed, 81 insertions(+), 2 deletions(-)
create mode 100644 testsuite/safe-links.test
diff --git a/testsuite/safe-links.test b/testsuite/safe-links.test
new file mode 100644
index 00000000..6e95a4b9
--- /dev/null
+++ b/testsuite/safe-links.test
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+. "$suitedir/rsync.fns"
+
+test_symlink() {
+ is_a_link "$1" || test_fail "File $1 is not a symlink"
+}
+
+test_regular() {
+ if [ ! -f "$1" ]; then
+ test_fail "File $1 is not regular file or not exists"
+ fi
+}
+
+test_notexist() {
+ if [ -e "$1" ]; then
+ test_fail "File $1 exists"
+ fi
+ if [ -h "$1" ]; then
+ test_fail "File $1 exists as a symlink"
+ fi
+}
+
+cd "$tmpdir"
+
+mkdir from
+
+mkdir "from/safe"
+mkdir "from/unsafe"
+
+mkdir "from/safe/files"
+mkdir "from/safe/links"
+
+touch "from/safe/files/file1"
+touch "from/safe/files/file2"
+touch "from/unsafe/unsafefile"
+
+ln -s ../files/file1 "from/safe/links/"
+ln -s ../files/file2 "from/safe/links/"
+ln -s ../../unsafe/unsafefile "from/safe/links/"
+ln -s a/a/a/../../../unsafe2 "from/safe/links/"
+
+#echo "LISTING FROM"
+#ls -lR from
+
+echo "rsync with relative path and just -a"
+$RSYNC -avv --safe-links from/safe/ to
+
+#echo "LISTING TO"
+#ls -lR to
+
+test_symlink to/links/file1
+test_symlink to/links/file2
+test_notexist to/links/unsafefile
+test_notexist to/links/unsafe2
diff --git a/testsuite/unsafe-byname.test b/testsuite/unsafe-byname.test
index 75e72014..d2e318ef 100644
--- a/testsuite/unsafe-byname.test
+++ b/testsuite/unsafe-byname.test
@@ -40,7 +40,7 @@ test_unsafe ..//../dest from/dir unsafe
test_unsafe .. from/file safe
test_unsafe ../.. from/file unsafe
test_unsafe ..//.. from//file unsafe
-test_unsafe dir/.. from safe
+test_unsafe dir/.. from unsafe
test_unsafe dir/../.. from unsafe
test_unsafe dir/..//.. from unsafe
diff --git a/util1.c b/util1.c
index da50ff1e..f260d398 100644
--- a/util1.c
+++ b/util1.c
@@ -1318,7 +1318,14 @@ int handle_partial_dir(const char *fname, int create)
*
* "src" is the top source directory currently applicable at the level
* of the referenced symlink. This is usually the symlink's full path
- * (including its name), as referenced from the root of the transfer. */
+ * (including its name), as referenced from the root of the transfer.
+ *
+ * NOTE: this also rejects dest names with a .. component in other
+ * than the first component of the name ie. it rejects names such as
+ * a/b/../x/y. This needs to be done as the leading subpaths 'a' or
+ * 'b' could later be replaced with symlinks such as a link to '.'
+ * resulting in the link being transferred now becoming unsafe
+ */
int unsafe_symlink(const char *dest, const char *src)
{
const char *name, *slash;
@@ -1328,6 +1335,23 @@ int unsafe_symlink(const char *dest, const char *src)
if (!dest || !*dest || *dest == '/')
return 1;
+ // reject destinations with /../ in the name other than at the start of the name
+ const char *dest2 = dest;
+ while (strncmp(dest2, "../", 3) == 0) {
+ dest2 += 3;
+ while (*dest2 == '/') {
+ // allow for ..//..///../foo
+ dest2++;
+ }
+ }
+ if (strstr(dest2, "/../"))
+ return 1;
+
+ // reject if the destination ends in /..
+ const size_t dlen = strlen(dest);
+ if (dlen > 3 && strcmp(&dest[dlen-3], "/..") == 0)
+ return 1;
+
/* find out what our safety margin is */
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
/* ".." segment starts the count over. "." segment is ignored. */
--
2.34.1

163
rsync-CVE-2024-12747.patch Normal file
View File

@ -0,0 +1,163 @@
diff --git a/checksum.c b/checksum.c
index cb21882..66e8089 100644
--- a/checksum.c
+++ b/checksum.c
@@ -406,7 +406,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
int32 remainder;
int fd;
- fd = do_open(fname, O_RDONLY, 0);
+ fd = do_open_checklinks(fname);
if (fd == -1) {
memset(sum, 0, file_sum_len);
return;
diff --git a/flist.c b/flist.c
index 087f9da..1783253 100644
--- a/flist.c
+++ b/flist.c
@@ -1390,7 +1390,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
if (st.st_size == 0) {
- int fd = do_open(fname, O_RDONLY, 0);
+ int fd = do_open_checklinks(fname);
if (fd >= 0) {
st.st_size = get_device_size(fd, fname);
close(fd);
diff --git a/generator.c b/generator.c
index 110db28..3f13bb9 100644
--- a/generator.c
+++ b/generator.c
@@ -1798,7 +1798,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
/* This early open into fd skips the regular open below. */
- if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0)
+ if ((fd = do_open_nofollow(fnamecmp, O_RDONLY)) >= 0)
real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp);
}
@@ -1867,7 +1867,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* open the file */
- if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+ if (fd < 0 && (fd = do_open_checklinks(fnamecmp)) < 0) {
rsyserr(FERROR, errno, "failed to open %s, continuing",
full_fname(fnamecmp));
pretend_missing:
diff --git a/receiver.c b/receiver.c
index 8031b8f..edfbb21 100644
--- a/receiver.c
+++ b/receiver.c
@@ -775,7 +775,7 @@ int recv_files(int f_in, int f_out, char *local_name)
if (fnamecmp != fname) {
fnamecmp = fname;
fnamecmp_type = FNAMECMP_FNAME;
- fd1 = do_open(fnamecmp, O_RDONLY, 0);
+ fd1 = do_open_nofollow(fnamecmp, O_RDONLY);
}
if (fd1 == -1 && basis_dir[0]) {
diff --git a/sender.c b/sender.c
index 2bbff2f..a4d46c3 100644
--- a/sender.c
+++ b/sender.c
@@ -350,7 +350,7 @@ void send_files(int f_in, int f_out)
exit_cleanup(RERR_PROTOCOL);
}
- fd = do_open(fname, O_RDONLY, 0);
+ fd = do_open_checklinks(fname);
if (fd == -1) {
if (errno == ENOENT) {
enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING;
diff --git a/syscall.c b/syscall.c
index 47c5ea5..c55ae5f 100644
--- a/syscall.c
+++ b/syscall.c
@@ -45,6 +45,8 @@ extern int preallocate_files;
extern int preserve_perms;
extern int preserve_executability;
extern int open_noatime;
+extern int copy_links;
+extern int copy_unsafe_links;
#ifndef S_BLKSIZE
# if defined hpux || defined __hpux__ || defined __hpux
@@ -793,3 +795,21 @@ cleanup:
return retfd;
#endif // O_NOFOLLOW, O_DIRECTORY
}
+
+/*
+ varient of do_open/do_open_nofollow which does do_open() if the
+ copy_links or copy_unsafe_links options are set and does
+ do_open_nofollow() otherwise
+
+ This is used to prevent a race condition where an attacker could be
+ switching a file between being a symlink and being a normal file
+
+ The open is always done with O_RDONLY flags
+ */
+int do_open_checklinks(const char *pathname)
+{
+ if (copy_links || copy_unsafe_links) {
+ return do_open(pathname, O_RDONLY, 0);
+ }
+ return do_open_nofollow(pathname, O_RDONLY);
+}
diff --git a/t_unsafe.c b/t_unsafe.c
index 010cac5..e10619a 100644
--- a/t_unsafe.c
+++ b/t_unsafe.c
@@ -28,6 +28,9 @@ int am_root = 0;
int am_sender = 1;
int read_only = 0;
int list_only = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
+
short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
int
diff --git a/tls.c b/tls.c
index e6b0708..858f8f1 100644
--- a/tls.c
+++ b/tls.c
@@ -49,6 +49,9 @@ int list_only = 0;
int link_times = 0;
int link_owner = 0;
int nsec_times = 0;
+int safe_symlinks = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
#ifdef SUPPORT_XATTRS
diff --git a/trimslash.c b/trimslash.c
index 1ec928c..f2774cd 100644
--- a/trimslash.c
+++ b/trimslash.c
@@ -26,6 +26,8 @@ int am_root = 0;
int am_sender = 1;
int read_only = 1;
int list_only = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
int
main(int argc, char **argv)
diff --git a/util1.c b/util1.c
index f260d39..d84bc41 100644
--- a/util1.c
+++ b/util1.c
@@ -365,7 +365,7 @@ int copy_file(const char *source, const char *dest, int tmpfilefd, mode_t mode)
int len; /* Number of bytes read into `buf'. */
OFF_T prealloc_len = 0, offset = 0;
- if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
+ if ((ifd = do_open_nofollow(source, O_RDONLY)) < 0) {
int save_errno = errno;
rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
errno = save_errno;

13
rsync-gcc14.patch Normal file
View File

@ -0,0 +1,13 @@
Index: rsync-3.3.0/configure.ac
===================================================================
--- rsync-3.3.0.orig/configure.ac
+++ rsync-3.3.0/configure.ac
@@ -412,7 +412,7 @@ AS_HELP_STRING([--disable-ipv6],[disable
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
-main()
+int main(void)
{
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
exit(1);

13
rsync-no-libattr.patch Normal file
View File

@ -0,0 +1,13 @@
Index: rsync-3.2.2/configure.ac
===================================================================
--- rsync-3.2.2.orig/configure.ac
+++ rsync-3.2.2/configure.ac
@@ -1309,7 +1309,7 @@ else
AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs (or equivalent)])
AC_DEFINE(SUPPORT_XATTRS, 1)
AC_DEFINE(NO_SYMLINK_USER_XATTRS, 1, [True if symlinks do not support user xattrs])
- AC_CHECK_LIB(attr,getxattr)
+ AC_SEARCH_LIBS([getxattr], [attr])
;;
darwin*)
AC_MSG_RESULT(Using OS X xattrs)

BIN
rsync-patches-3.3.0.tar.gz (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
-----BEGIN PGP SIGNATURE-----
iF0EABECAB0WIQQASMiwJtTJbw5YnC9shZ+xS5aoxQUCZhF6vQAKCRBshZ+xS5ao
xcOpAJ0e/0uM2Ds98F7lwsTWiYdsJJ4EGwCfU4SaBIySxtKPdHh0Qy6Y1dt8uTc=
=dZu7
-----END PGP SIGNATURE-----

12
rsync-run-dir.patch Normal file
View File

@ -0,0 +1,12 @@
diff -ur rsync-3.3.0.old/rsync.h rsync-3.3.0/rsync.h
--- rsync-3.3.0.old/rsync.h 2022-10-16 19:28:58.000000000 +0200
+++ rsync-3.3.0/rsync.h 2024-08-26 11:31:14.458919925 +0200
@@ -30,7 +30,7 @@
/* RSYNCD_SYSCONF is now set in config.h */
#define RSYNCD_USERCONF "rsyncd.conf"
-#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock"
+#define DEFAULT_LOCK_FILE "/run/rsyncd.lock"
#define URL_PREFIX "rsync://"
#define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */

75
rsync-usr-etc.patch Normal file
View File

@ -0,0 +1,75 @@
diff -ur a/clientserver.c b/clientserver.c
--- a/clientserver.c 2023-11-28 17:12:41.643268046 +0100
+++ b/clientserver.c 2023-11-28 17:25:30.476279700 +0100
@@ -1261,10 +1261,16 @@
static int load_config(int globals_only)
{
if (!config_file) {
- if (am_daemon < 0 && am_root <= 0)
+ if (am_daemon < 0 && am_root <= 0) {
config_file = RSYNCD_USERCONF;
- else
+ } else {
config_file = RSYNCD_SYSCONF;
+#ifdef RSYNCD_DISTCONF
+ STRUCT_STAT st;
+ if (do_stat(RSYNCD_SYSCONF, &st) != 0)
+ config_file = RSYNCD_DISTCONF;
+#endif
+ }
}
return lp_load(config_file, globals_only);
}
diff -ur a/configure.ac b/configure.ac
--- a/configure.ac 2023-11-28 17:12:41.647268046 +0100
+++ b/configure.ac 2023-11-28 17:40:15.678280030 +0100
@@ -175,7 +175,7 @@
AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine])
AC_ARG_WITH(rsyncd-conf,
- AS_HELP_STRING([--with-rsyncd-conf=PATH],[set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
+ AS_HELP_STRING([--with-rsyncd-conf=PATH],[set user/admin defined configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]),
[ if test ! -z "$with_rsyncd_conf" ; then
case $with_rsyncd_conf in
yes|no)
@@ -193,7 +193,27 @@
fi ],
[ RSYNCD_SYSCONF="/etc/rsyncd.conf" ])
-AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server])
+AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of user/admin defined configuration file for rsync server])
+
+AC_ARG_WITH(rsyncd-distconf,
+ AS_HELP_STRING([--with-rsyncd-distconf=PATH],[set vendor configuration file for rsync server to PATH (default: not set)]),
+ [ if test ! -z "$with_rsyncd_distconf" ; then
+ case $with_rsyncd_distconf in
+ yes|no)
+ RSYNCD_DISTCONF="/usr/etc/rsyncd.conf"
+ ;;
+ /*)
+ RSYNCD_DISTCONF="$with_rsyncd_distconf"
+ ;;
+ *)
+ AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-distconf=PATH)
+ ;;
+ esac
+ fi
+ ],
+ [])
+
+AC_DEFINE_UNQUOTED(RSYNCD_DISTCONF, "$RSYNCD_DISTCONF", [location of vendor configuration file for rsync server])
AC_ARG_WITH(rsh,
AS_HELP_STRING([--with-rsh=CMD],[set remote shell command to CMD (default: ssh)]))
diff -ur a/rsyncd.conf.5.md b/rsyncd.conf.5.md
--- a/rsyncd.conf.5.md 2023-11-28 17:12:41.643268046 +0100
+++ b/rsyncd.conf.5.md 2023-11-29 13:08:32.125333095 +0100
@@ -1235,7 +1235,7 @@
## FILES
-/etc/rsyncd.conf or rsyncd.conf
+rsyncd.conf or /etc/rsyncd.conf or /usr/etc/rsyncd.conf
## SEE ALSO

1377
rsync.changes Normal file

File diff suppressed because it is too large Load Diff

32
rsync.keyring Normal file
View File

@ -0,0 +1,32 @@
pub 1024D/4B96A8C5 2003-12-19
uid Wayne Davison <wayned@users.sourceforge.net>
uid Wayne Davison <wayned@samba.org>
sub 1024g/29C67D63 2003-12-19
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.9 (GNU/Linux)
mQGiBD/ja2cRBACZqtQ/VnuWd2TA/T4nFitXPOF//7uterTWZVMDBrSE3tJdW1lv
90z2g2RJKktJTC3yjs82IH6wWvvFsHDPGXQRuoBr0dPYHBaVhKX85uewigHiE2M1
1Ub8Vv1c/JDGAh1cNmCAWazghV+emamrWJWq0f0hz5eqq4LCcPwo4riUVwCg9W37
YAR8Z4NHa6FWjrEKjl2NIMUD/iXJnp6qJFMK9Fs+2dWyL1m/mRb0h+I/cqgpkUvo
gRhL95Jttg2QQtXJWCsB3hA/L/2Iu2bV8iS1aRlZQsAWogA3/m56ROs8cIyN4ouj
1dpPoG7sKGA8BTvXxuSF9l6ngx7208iX+xiQCDeGfBtBFBy70iJxTFGzp2mP3IiP
pwWtBACJ6l8UPwSRmp0Hz/N6H4RkzqGQnvYsMba/uPkRYou/14JsEGCQqjSB99UX
hsPg9wubCEpo3YFTf1p1j3OlbOhiiMkRFwyYaT1fqGjQK0w8hQ1yXHxbXffnz6e3
gKELz7fNQxS0L/tZkNOT7uyGuwnPsUDCBAzDPMwYVIFRo+MKZLQgV2F5bmUgRGF2
aXNvbiA8d2F5bmVkQHNhbWJhLm9yZz6IWwQTEQIAGwUCP+NrZwYLCQgHAwIDFQID
AxYCAQIeAQIXgAAKCRBshZ+xS5aoxbKaAJ98/UHW+BAmnsWCvCXYw5xAvjKQuwCg
7rJUYSl3xpb6YmIaBbyyw5QTKiC0LFdheW5lIERhdmlzb24gPHdheW5lZEB1c2Vy
cy5zb3VyY2Vmb3JnZS5uZXQ+iF4EExECAB4FAkFgW4ACGwMGCwkIBwMCAxUCAwMW
AgECHgECF4AACgkQbIWfsUuWqMXxFQCg9Dgb5SnWZroPGl25DL2OYFHdqV4An0N2
QQj0mVi18JgadtS4xv7yNiDauQENBD/ja3EQBADkZadXo4zP2P9XjCP9jCel2hIp
E/khYifgu8sLYQ3VOaVM6iczw71a+iM3C44CddioGNv0svJ/cEttbtAE5zZIfqm0
Rd/CYR+kqOkUydss736olRh+4lXLi9dAzDwHoEmlO+i95V6bDdSCAF9+XLhpfUY/
xtgistlUGTd+wyeQMwADBQP9HXUGOcR18VJsQtFOmXaXv9MSKZYMjCf9R5Z7gcPF
PSIWINyUvMEgnLIrUKJ7pgoA6cLDnYm/lBVP801u5C+D4s79oCnjS21wlOxA2Go0
hxG6XpT9mwBOWk4uZUK+g8Emeu7Vi6l3XwH8fACdCIfp3wKlqH/qtkqN7Gts95TM
59uIRgQYEQIABgUCP+NrcQAKCRBshZ+xS5aoxUisAKC2tk0y7PNjh9C9vbfx3fdA
gqiD8gCgg6qjwVbeddcrA0a84BB3zXnb93A=
=0IcW
-----END PGP PUBLIC KEY BLOCK-----

236
rsync.spec Normal file
View File

@ -0,0 +1,236 @@
#
# spec file for package rsync
#
# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%if 0%{?suse_version} >= 1550
%bcond_without xxhash
%else
%bcond_with xxhash
%endif
%if 0%{?suse_version} < 1550
%bcond_without gcc11
%else
%bcond_with gcc11
%endif
%if 0%{?suse_version} < 1600
%bcond_without slp
%else
%bcond_with slp
%endif
Name: rsync
Version: 3.3.0
Release: 0
Summary: Versatile tool for fast incremental file transfer
License: GPL-3.0-or-later
Group: Productivity/Networking/Other
URL: https://rsync.samba.org/
Source: https://rsync.samba.org/ftp/rsync/src/rsync-%{version}.tar.gz
Source1: https://rsync.samba.org/ftp/rsync/src/rsync-patches-%{version}.tar.gz
Source2: logrotate.rsync
Source3: rsyncd.socket
Source4: rsyncd.rc
Source5: rsyncd.conf
Source6: rsyncd.secrets
Source8: rsyncd.service
Source9: rsyncd@.service
Source10: https://rsync.samba.org/ftp/rsync/src/rsync-%{version}.tar.gz.asc
Source11: https://rsync.samba.org/ftp/rsync/src/rsync-patches-%{version}.tar.gz.asc
Source12: %{name}.keyring
Source13: rsyncd
Patch0: rsync-no-libattr.patch
Patch1: rsync-gcc14.patch
Patch2: rsync-usr-etc.patch
Patch3: rsync-run-dir.patch
# https://github.com/RsyncProject/rsync/pull/639
Patch5: rsyncd-return-from-list-command-with-0.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12084 bsc#1234100
Patch6: rsync-CVE-2024-12084-overflow-01.patch
Patch7: rsync-CVE-2024-12084-overflow-02.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12085 bsc#1234101
Patch8: rsync-CVE-2024-12085.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12086 bsc#1234102
Patch9: rsync-CVE-2024-12086_01.patch
Patch10: rsync-CVE-2024-12086_02.patch
Patch11: rsync-CVE-2024-12086_03.patch
Patch12: rsync-CVE-2024-12086_04.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12087 bsc#1234103
Patch13: rsync-CVE-2024-12087_01.patch
Patch14: rsync-CVE-2024-12087_02.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12088 bsc#1234104
Patch15: rsync-CVE-2024-12088.patch
# PATCH-FIX-UPSTREAM: rsync CVE-2024-12088 bsc#1235475
Patch16: rsync-CVE-2024-12747.patch
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: c++_compiler
BuildRequires: libacl-devel
BuildRequires: liblz4-devel
BuildRequires: libzstd-devel
BuildRequires: pkgconfig
BuildRequires: popt-devel
BuildRequires: systemd-rpm-macros
BuildRequires: zlib-devel
%if %{with xxhash}
BuildRequires: pkgconfig(libxxhash) >= 0.8.0
%endif
%if %{with gcc11}
BuildRequires: gcc11-c++
%endif
%if %{with slp}
BuildRequires: openslp-devel
%endif
BuildRequires: pkgconfig(openssl)
Requires(post): grep
Requires(post): sed
Recommends: logrotate
%description
Rsync is a fast and extraordinarily versatile file copying tool. It can copy
locally, to/from another host over any remote shell, or to/from a remote rsync
daemon. It offers a large number of options that control every aspect of its
behavior and permit very flexible specification of the set of files to be
copied. It is famous for its delta-transfer algorithm, which reduces the amount
of data sent over the network by sending only the differences between the
source files and the existing files in the destination. Rsync is widely used
for backups and mirroring and as an improved copy command for everyday use.
%prep
%setup -q -b 1
rm -f zlib/*.h zlib/*.c
%if %{with slp}
patch -p1 < patches/slp.diff
%endif
%autopatch -p1
%build
autoreconf -fiv
%if %{with gcc11}
export CC=gcc-11
export CXX=g++-11
%endif
export CFLAGS="%{optflags} -fPIC -DPIC -fPIE"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="-Wl,-z,relro,-z,now -fPIE -pie"
%configure \
--with-included-popt=no \
--with-included-zlib=no \
--disable-debug \
%if 0%{?suse_version} > 1500
--with-rsyncd-distconf=%{_distconfdir}/rsyncd.conf \
%endif
%if !%{with xxhash}
--disable-xxhash\
%endif
%ifarch x86_64
--enable-roll-simd \
%endif
%if %{with slp}
--enable-slp \
%endif
--enable-acl-support \
--enable-xattr-support
%make_build reconfigure
%make_build
%check
chmod +x support/*
%make_build check
chmod -x support/*
%install
%make_install
rm -f %{buildroot}%{_sbindir}/rsyncd
install -d %{buildroot}%{_sysconfdir}/init.d
install -d %{buildroot}%{_sysconfdir}/xinetd.d
install -d %{buildroot}%{_sbindir}
install -m 755 %{SOURCE13} %{buildroot}%{_sbindir}/rsyncd
install -m 755 support/rsyncstats %{buildroot}%{_bindir}
%if 0%{?suse_version} > 1500
install -d %{buildroot}%{_distconfdir}/logrotate.d
install -m 644 %{SOURCE2} %{buildroot}%{_distconfdir}/logrotate.d/rsync
install -m 644 %{SOURCE5} %{buildroot}%{_distconfdir}/rsyncd.conf
install -m 600 %{SOURCE6} %{buildroot}%{_distconfdir}/rsyncd.secrets
echo "# This is a template only. Create your own entries in /etc/rsyncd.secrets" >>%{buildroot}%{_distconfdir}/rsyncd.secrets
echo
%else
install -d %{buildroot}%{_sysconfdir}/logrotate.d
install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/logrotate.d/rsync
install -m 644 %{SOURCE5} %{buildroot}%{_sysconfdir}/rsyncd.conf
install -m 600 %{SOURCE6} %{buildroot}%{_sysconfdir}/rsyncd.secrets
%endif
install -D -m 0644 %{SOURCE9} %{buildroot}%{_unitdir}/rsyncd@.service
install -D -m 0644 %{SOURCE8} %{buildroot}%{_unitdir}/rsyncd.service
install -D -m 0644 %{SOURCE3} %{buildroot}%{_unitdir}/rsyncd.socket
ln -sf service %{buildroot}%{_sbindir}/rcrsyncd
chmod -x support/*
%pre
%service_add_pre rsyncd.service
%if 0%{?suse_version} > 1500
# Prepare for migration to /usr/etc; save any old .rpmsave
for i in logrotate.d/rsync rsyncd.conf rsyncd.secrets; do
test -f %{_sysconfdir}/${i}.rpmsave && mv -v %{_sysconfdir}/${i}.rpmsave %{_sysconfdir}/${i}.rpmsave.old ||:
done
%endif
%if 0%{?suse_version} > 1500
%posttrans
# Migration to /usr/etc, restore just created .rpmsave
for i in logrotate.d/rsync rsyncd.conf rsyncd.secrets; do
test -f %{_sysconfdir}/${i}.rpmsave && mv -v %{_sysconfdir}/${i}.rpmsave %{_sysconfdir}/${i} ||:
done
%endif
%preun
%service_del_preun rsyncd.service
%post
%service_add_post rsyncd.service
%postun
%service_del_postun rsyncd.service
%files
%license COPYING
%doc NEWS.md README.md tech_report.tex support/
%{_unitdir}/rsyncd@.service
%{_unitdir}/rsyncd.service
%{_unitdir}/rsyncd.socket
%if 0%{?suse_version} > 1500
%{_distconfdir}/logrotate.d/rsync
%{_distconfdir}/rsyncd.conf
%{_distconfdir}/rsyncd.secrets
%else
%config(noreplace) %{_sysconfdir}/logrotate.d/rsync
%config(noreplace) %{_sysconfdir}/rsyncd.conf
%config(noreplace) %{_sysconfdir}/rsyncd.secrets
%endif
%{_sbindir}/rcrsyncd
%{_sbindir}/rsyncd
%{_bindir}/rsyncstats
%{_bindir}/rsync
%{_bindir}/rsync-ssl
%{_mandir}/man1/rsync.1%{?ext_man}
%{_mandir}/man1/rsync-ssl.1%{?ext_man}
%{_mandir}/man5/rsyncd.conf.5%{?ext_man}
%changelog

6
rsyncd Normal file
View File

@ -0,0 +1,6 @@
#!/bin/sh
# We need this wrapper instead of a plain symlink to be able to set
# a different SELinux label on this
exec -a rsyncd /usr/bin/rsync "$@"

View File

@ -0,0 +1,33 @@
From bfb95e4a60c27ec0f9bb4668cc6163f5cfb3e635 Mon Sep 17 00:00:00 2001
From: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
Date: Fri, 6 Sep 2024 01:39:32 +0200
Subject: [PATCH] Return from #list command with 0
The "#list" command should not be treated as a failure when it is
both a legitimate request by the client, and correctly answered by the
server. It is commonly used for assessing whether a rsync endpoint is
healthy, having it return with a non-zero exit code causes misleading
error reports, and, in case of socket activation, failed service
instances on the server.
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
---
clientserver.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clientserver.c b/clientserver.c
index 7c897abc..c507ea91 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -1371,7 +1371,7 @@ int start_daemon(int f_in, int f_out)
rprintf(FLOG, "module-list request from %s (%s)\n",
host, addr);
send_listing(f_out);
- return -1;
+ return 0;
}
if (*line == '#') {
--
2.46.0

16
rsyncd.conf Normal file
View File

@ -0,0 +1,16 @@
gid = users
read only = true
use chroot = true
transfer logging = true
log format = %h %o %f %l %b
log file = /var/log/rsyncd.log
pid file = /run/rsyncd.pid
hosts allow = trusted.hosts
slp refresh = 300
use slp = false
#[Example]
# path = /home/Example
# comment = An Example
# auth users = user
# secrets file = /etc/rsyncd.secrets

137
rsyncd.rc Normal file
View File

@ -0,0 +1,137 @@
#! /bin/sh
# Copyright (c) 1996, 1997, 1998 S.u.S.E. GmbH
# Copyright (c) 1998, 1999, 2000, 2001 SuSE GmbH
# Copyright (c) 2002 SuSE Linux AG
#
# Author: Kurt Garloff <feedback@suse.de>
#
# init.d/rsyncd
#
# and symbolic its link
#
# /sbin/rcrsyncd
#
# System startup script for the rsync daemon
#
### BEGIN INIT INFO
# Provides: rsync
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Should-Start: slpd
# Should-Stop: slpd
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Description: Start the rsync server daemon
# Short-Description: Start the rsync server daemon
### END INIT INFO
RSYNCD_BIN=/usr/sbin/rsyncd
test -x $RSYNCD_BIN || exit 5
RSYNCD_PID=/var/run/rsyncd.pid
# Shell functions sourced from /etc/rc.status:
# rc_check check and set local and overall rc status
# rc_status check and set local and overall rc status
# rc_status -v ditto but be verbose in local rc status
# rc_status -v -r ditto and clear the local rc status
# rc_failed set local and overall rc status to failed
# rc_failed <num> set local and overall rc status to <num><num>
# rc_reset clear local rc status (overall remains)
# rc_exit exit appropriate to overall rc status
. /etc/rc.status
# First reset status of this service
rc_reset
# Return values acc. to LSB for all commands but status:
# 0 - success
# 1 - generic or unspecified error
# 2 - invalid or excess argument(s)
# 3 - unimplemented feature (e.g. "reload")
# 4 - insufficient privilege
# 5 - program is not installed
# 6 - program is not configured
# 7 - program is not running
#
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signalling is not supported) are
# considered a success.
case "$1" in
start)
echo -n "Starting rsync daemon"
## Start daemon with startproc(8). If this fails
## the echo return value is set appropriate.
# NOTE: startproc return 0, even if service is
# already running to match LSB spec.
startproc -p $RSYNCD_PID -t 1 $RSYNCD_BIN --daemon
# Remember status and be verbose
rc_status -v
;;
stop)
echo -n "Shutting down rsync daemon"
## Stop daemon with killproc(8) and if this fails
## set echo the echo return value.
killproc -p $RSYNCD_PID $RSYNCD_BIN
# Remember status and be verbose
rc_status -v
;;
try-restart)
## Stop the service and if this succeeds (i.e. the
## service was running before), start it again.
## Note: try-restart is not (yet) part of LSB (as of 0.7.5)
$0 status >/dev/null && $0 restart
# Remember status and be quiet
rc_status
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
# Remember status and be quiet
rc_status
;;
force-reload)
## Signal the daemon to reload its config. Most daemons
## do this on signal 1 (SIGHUP).
## If it does not support it, restart.
echo "Reload service rsync"
"$0" restart
rc_status -v
;;
reload)
# rsyncd does not catch SIGHUP
echo -n "Reload service rsync"
rc_failed 3
rc_status -v
;;
status)
echo -n "Checking for rsync daemon: "
## Check status with checkproc(8), if process is running
## checkproc will return with exit status 0.
# Status has a slightly different for the status command:
# 0 - service running
# 1 - service dead, but /var/run/ pid file exists
# 2 - service dead, but /var/lock/ lock file exists
# 3 - service not running
# NOTE: checkproc returns LSB compliant status values.
checkproc -p $RSYNCD_PID $RSYNCD_BIN
rc_status -v
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}"
exit 1
;;
esac
rc_exit

1
rsyncd.secrets Normal file
View File

@ -0,0 +1 @@
# user:passwd

22
rsyncd.service Normal file
View File

@ -0,0 +1,22 @@
[Unit]
Description=Start the rsync server daemon
After=network.target
ConditionPathExists=/etc/rsyncd.conf
[Service]
ExecStart=/usr/sbin/rsyncd --daemon --no-detach
IOSchedulingClass=idle
CPUSchedulingPolicy=batch
PrivateTmp=true
# added automatically, for details please see
# https://en.opensuse.org/openSUSE:Security_Features#Systemd_hardening_effort
ProtectHostname=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
# end of automatic additions
[Install]
WantedBy=multi-user.target

10
rsyncd.socket Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=Rsync Server Socket
Conflicts=rsyncd.service
[Socket]
ListenStream=873
Accept=yes
[Install]
WantedBy=sockets.target

11
rsyncd@.service Normal file
View File

@ -0,0 +1,11 @@
[Unit]
Description=Start the rsync server daemon
After=network.target
ConditionPathExists=/etc/rsyncd.conf
[Service]
ExecStart=/usr/sbin/rsyncd --daemon --no-detach
IOSchedulingClass=idle
CPUSchedulingPolicy=batch
PrivateTmp=true
StandardInput=socket