diff mbox series

[scarthgap,6/6] rsync: fix CVE-2024-12747

Message ID 20250116151509.1939178-6-archana.polampalli@windriver.com
State Under Review
Delegated to: Steve Sakoman
Headers show
Series [scarthgap,1/6] rsync: fix CVE-2024-12084 | expand

Commit Message

Polampalli, Archana Jan. 16, 2025, 3:15 p.m. UTC
From: Archana Polampalli <archana.polampalli@windriver.com>

A flaw was found in rsync. This vulnerability arises from a race condition during
rsync's handling of symbolic links. Rsync's default behavior when encountering
symbolic links is to skip them. If an attacker replaced a regular file with a
symbolic link at the right time, it was possible to bypass the default behavior
and traverse symbolic links. Depending on the privileges of the rsync process,
an attacker could leak sensitive information, potentially leading to privilege escalation.

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 .../rsync/files/CVE-2024-12747.patch          | 192 ++++++++++++++++++
 meta/recipes-devtools/rsync/rsync_3.2.7.bb    |   1 +
 2 files changed, 193 insertions(+)
 create mode 100644 meta/recipes-devtools/rsync/files/CVE-2024-12747.patch
diff mbox series

Patch

diff --git a/meta/recipes-devtools/rsync/files/CVE-2024-12747.patch b/meta/recipes-devtools/rsync/files/CVE-2024-12747.patch
new file mode 100644
index 0000000000..b1dd0a03b9
--- /dev/null
+++ b/meta/recipes-devtools/rsync/files/CVE-2024-12747.patch
@@ -0,0 +1,192 @@ 
+From 0590b09d9a34ae72741b91ec0708a820650198b0 Mon Sep 17 00:00:00 2001
+From: Andrew Tridgell <andrew@tridgell.net>
+Date: Wed, 18 Dec 2024 08:59:42 +1100
+Subject: [PATCH] fixed symlink race condition in sender
+
+when we open a file that we don't expect to be a symlink use
+O_NOFOLLOW to prevent a race condition where an attacker could change
+a file between being a normal file and a symlink
+
+CVE: CVE-2024-12747
+
+Upstream-Status: Backport [https://git.samba.org/?p=rsync.git;a=commit;h=0590b09d9a34ae72741b91ec0708a820650198b0]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ checksum.c  |  2 +-
+ flist.c     |  2 +-
+ generator.c |  4 ++--
+ receiver.c  |  2 +-
+ sender.c    |  2 +-
+ syscall.c   | 20 ++++++++++++++++++++
+ t_unsafe.c  |  3 +++
+ tls.c       |  3 +++
+ trimslash.c |  2 ++
+ util1.c     |  2 +-
+ 10 files changed, 35 insertions(+), 7 deletions(-)
+
+diff --git a/checksum.c b/checksum.c
+index cb21882c..66e80896 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 087f9da6..17832533 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 110db28f..3f13bb95 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 8031b8f4..edfbb210 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 2bbff2fa..a4d46c39 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 081357bb..8cea2900 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
+@@ -788,3 +790,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 010cac50..e10619a2 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 e6b0708a..858f8f10 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 1ec928ca..f2774cd7 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 f260d398..d84bc414 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;
+--
+2.40.0
diff --git a/meta/recipes-devtools/rsync/rsync_3.2.7.bb b/meta/recipes-devtools/rsync/rsync_3.2.7.bb
index 169650fe91..d0796d3c12 100644
--- a/meta/recipes-devtools/rsync/rsync_3.2.7.bb
+++ b/meta/recipes-devtools/rsync/rsync_3.2.7.bb
@@ -26,6 +26,7 @@  SRC_URI = "https://download.samba.org/pub/${BPN}/src/${BP}.tar.gz \
            file://CVE-2024-12087-0002.patch \
            file://CVE-2024-12087-0003.patch \
            file://CVE-2024-12088.patch \
+           file://CVE-2024-12747.patch \
            "
 SRC_URI[sha256sum] = "4e7d9d3f6ed10878c58c5fb724a67dacf4b6aac7340b13e488fb2dc41346f2bb"