163 lines
4.9 KiB
Diff
163 lines
4.9 KiB
Diff
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.3/checksum.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/checksum.c
|
|
+++ rsync-3.1.3/checksum.c
|
|
@@ -200,7 +200,7 @@ void file_checksum(const char *fname, co
|
|
|
|
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.3/generator.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/generator.c
|
|
+++ rsync-3.1.3/generator.c
|
|
@@ -1828,7 +1828,7 @@ static void recv_generator(char *fname,
|
|
}
|
|
|
|
/* 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:
|
|
Index: rsync-3.1.3/receiver.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/receiver.c
|
|
+++ rsync-3.1.3/receiver.c
|
|
@@ -758,7 +758,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.3/sender.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/sender.c
|
|
+++ rsync-3.1.3/sender.c
|
|
@@ -335,7 +335,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.3/syscall.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/syscall.c
|
|
+++ rsync-3.1.3/syscall.c
|
|
@@ -45,6 +45,8 @@ extern int preallocate_files;
|
|
extern int preserve_perms;
|
|
extern int preserve_executability;
|
|
extern int noatime;
|
|
+extern int copy_links;
|
|
+extern int copy_unsafe_links;
|
|
|
|
#ifndef S_BLKSIZE
|
|
# if defined hpux || defined __hpux__ || defined __hpux
|
|
@@ -659,3 +661,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.3/t_unsafe.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/t_unsafe.c
|
|
+++ rsync-3.1.3/t_unsafe.c
|
|
@@ -31,6 +31,9 @@ int list_only = 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];
|
|
|
|
/* This is to make syscall.o shut up. */
|
|
Index: rsync-3.1.3/tls.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/tls.c
|
|
+++ rsync-3.1.3/tls.c
|
|
@@ -54,6 +54,9 @@ int preserve_executability = 0;
|
|
// int preallocate_files = 0;
|
|
// int inplace = 0;
|
|
int noatime = 0;
|
|
+int safe_symlinks = 0;
|
|
+int copy_links = 0;
|
|
+int copy_unsafe_links = 0;
|
|
|
|
#ifdef SUPPORT_XATTRS
|
|
|
|
Index: rsync-3.1.3/trimslash.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/trimslash.c
|
|
+++ rsync-3.1.3/trimslash.c
|
|
@@ -31,6 +31,8 @@ int preserve_executability = 0;
|
|
// int preallocate_files = 0;
|
|
// int inplace = 0;
|
|
int noatime = 0;
|
|
+int copy_links = 0;
|
|
+int copy_unsafe_links = 0;
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
Index: rsync-3.1.3/util.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/util.c
|
|
+++ rsync-3.1.3/util.c
|
|
@@ -462,7 +462,7 @@ int copy_file(const char *source, const
|
|
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;
|