File rsync-CVE-2024-12747.patch of Package rsync.37257
From f45f48055e548851bc7230f454dfeba139be6c04 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
---
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(-)
Index: rsync-3.1.0/checksum.c
===================================================================
--- rsync-3.1.0.orig/checksum.c
+++ rsync-3.1.0/checksum.c
@@ -115,7 +115,7 @@ void file_checksum(char *fname, char *su
memset(sum, 0, MAX_DIGEST_LEN);
- fd = do_open(fname, O_RDONLY, 0);
+ fd = do_open_checklinks(fname);
if (fd == -1)
return;
Index: rsync-3.1.0/generator.c
===================================================================
--- rsync-3.1.0.orig/generator.c
+++ rsync-3.1.0/generator.c
@@ -1799,7 +1799,7 @@ static void recv_generator(char *fname,
}
/* open the file */
- if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+ if ((fd = do_open_nofollow(fnamecmp, O_RDONLY)) < 0) {
rsyserr(FERROR, errno, "failed to open %s, continuing",
full_fname(fnamecmp));
pretend_missing:
Index: rsync-3.1.0/receiver.c
===================================================================
--- rsync-3.1.0.orig/receiver.c
+++ rsync-3.1.0/receiver.c
@@ -761,7 +761,7 @@ int recv_files(int f_in, int f_out, char
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]) {
Index: rsync-3.1.0/sender.c
===================================================================
--- rsync-3.1.0.orig/sender.c
+++ rsync-3.1.0/sender.c
@@ -330,7 +330,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
Index: rsync-3.1.0/syscall.c
===================================================================
--- rsync-3.1.0.orig/syscall.c
+++ rsync-3.1.0/syscall.c
@@ -42,6 +42,8 @@ extern int read_only;
extern int list_only;
extern int preserve_perms;
extern int preserve_executability;
+extern int copy_links;
+extern int copy_unsafe_links;
#define RETURN_ERROR_IF(x,e) \
do { \
@@ -570,3 +572,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);
+}
Index: rsync-3.1.0/t_unsafe.c
===================================================================
--- rsync-3.1.0.orig/t_unsafe.c
+++ rsync-3.1.0/t_unsafe.c
@@ -28,6 +28,8 @@ 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;
int human_readable = 0;
int preserve_perms = 0;
int preserve_executability = 0;
Index: rsync-3.1.0/tls.c
===================================================================
--- rsync-3.1.0.orig/tls.c
+++ rsync-3.1.0/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;
int preserve_perms = 0;
int preserve_executability = 0;
Index: rsync-3.1.0/trimslash.c
===================================================================
--- rsync-3.1.0.orig/trimslash.c
+++ rsync-3.1.0/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 preserve_perms = 0;
int preserve_executability = 0;