Compare commits

...

No commits in common. "c8" and "c8-beta" have entirely different histories.
c8 ... c8-beta

5 changed files with 1 additions and 266 deletions

View File

@ -1,14 +0,0 @@
diff --git a/match.c b/match.c
index 36e78ed..dfd6af2 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;

View File

@ -1,36 +0,0 @@
diff --git a/flist.c b/flist.c
index 464d556..087f9da 100644
--- a/flist.c
+++ b/flist.c
@@ -2584,6 +2584,19 @@ struct file_list *recv_file_list(int f, int dir_ndx)
init_hard_links();
#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);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ file->flags |= FLAG_GOT_DIR_FLIST;
+ }
+
flist = flist_new(0, "recv_file_list");
if (inc_recurse) {
diff --git a/rsync.h b/rsync.h
index b357dad..bc9abac 100644
--- a/rsync.h
+++ b/rsync.h
@@ -83,6 +83,7 @@
#define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */
#define FLAG_TIME_FAILED (1<<11)/* generator */
#define FLAG_MOD_NSEC (1<<12) /* sender/receiver/generator */
+#define FLAG_GOT_DIR_FLIST (1<<13)/* sender/receiver/generator - dir_flist only */
/* These flags are passed to functions but not stored. */

View File

@ -1,57 +0,0 @@
diff --git a/testsuite/unsafe-byname.test b/testsuite/unsafe-byname.test
index 75e7201..d2e318e 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/util.c b/util.c
index da50ff1..f260d39 100644
--- a/util.c
+++ b/util.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. */

View File

@ -1,141 +0,0 @@
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)
memset(sum, 0, MAX_DIGEST_LEN);
- fd = do_open(fname, O_RDONLY, 0);
+ fd = do_open_checklinks(fname);
if (fd == -1)
return;
diff --git a/generator.c b/generator.c
index 110db28..3f13bb9 100644
--- a/generator.c
+++ b/generator.c
@@ -1867,7 +1867,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* open the file */
- if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+ if ((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 (fd1 == -1 && protocol_version < 29) {
if (fnamecmp != fname) {
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
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 preallocate_files;
extern int preserve_perms;
extern int preserve_executability;
+extern int copy_links;
+extern int copy_unsafe_links;
#ifndef S_BLKSIZE
# if defined hpux || defined __hpux__ || defined __hpux
@@ -575,3 +575,21 @@ int do_open_nofollow(const char *pathname, int flags)
return fd;
}
+
+/*
+ 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 human_readable = 0;
int preserve_perms = 0;
int preserve_executability = 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 preserve_executability = 0;
int preallocate_files = 0;
int inplace = 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 preserve_executability = 0;
int preallocate_files = 0;
int inplace = 0;
+int copy_links = 0;
+int copy_unsafe_links = 0;
int
main(int argc, char **argv)
diff --git a/util.c b/util.c
index f260d39..d84bc41 100644
--- a/util.c
+++ b/util.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;

View File

@ -9,7 +9,7 @@
Summary: A program for synchronizing files over a network
Name: rsync
Version: 3.1.3
Release: 21%{?dist}
Release: 19%{?dist}.1
Group: Applications/Internet
URL: http://rsync.samba.org/
@ -42,10 +42,6 @@ Patch11: rsync-3.1.3-cve-2022-29154.patch
Patch12: rsync-3.1.3-cve-2022-37434.patch
Patch13: rsync-3.1.3-filtering-rules.patch
Patch14: rsync-3.1.3-missing-xattr-filter.patch
Patch15: rsync-3.1.3-cve-2024-12085.patch
Patch16: rsync-3.1.3-cve-2024-12087.patch
Patch17: rsync-3.1.3-cve-2024-12088.patch
Patch18: rsync-3.1.3-cve-2024-12747.patch
%description
Rsync uses a reliable algorithm to bring remote and host files into
@ -98,10 +94,6 @@ patch -p1 -i patches/copy-devices.diff
%patch12 -p1 -b .cve-2022-37434
%patch13 -p1 -b .filtering-rules
%patch14 -p1 -b .xattr-filter
%patch15 -p1 -b .cve-2024-12085
%patch16 -p1 -b .cve-2024-12087
%patch17 -p1 -b .cve-2024-12088
%patch18 -p1 -b .cve-2024-12747
%build
%configure
@ -148,15 +140,6 @@ chmod -x support/*
%systemd_postun_with_restart rsyncd.service
%changelog
* Tue Feb 04 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-21
- Resolves: RHEL-70207 - Path traversal vulnerability in rsync
* Mon Feb 03 2025 Michal Ruprich <mruprich@redhat.com> - 3.1.3-20
- Resolves: RHEL-70207 - Path traversal vulnerability in rsync
- Resolves: RHEL-70209 - --safe-links option bypass leads to path traversal
- Resolves: RHEL-72502 - Race Condition in rsync Handling Symbolic Links
- Resolves: RHEL-70157 - Info Leak via Uninitialized Stack Contents
* Wed Nov 02 2022 Michal Ruprich <mruprich@redhat.com> - 3.1.3-19.1
- Resolves: #2139118 - rsync-daemon fail on 3.1.3