265 lines
7.6 KiB
Diff
265 lines
7.6 KiB
Diff
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(+)
|
|
|
|
Index: rsync-3.1.3/syscall.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/syscall.c
|
|
+++ rsync-3.1.3/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;
|
|
@@ -578,3 +580,75 @@ int do_open_nofollow(const char *pathnam
|
|
|
|
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
|
|
+}
|
|
Index: rsync-3.1.3/ifuncs.h
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/ifuncs.h
|
|
+++ rsync-3.1.3/ifuncs.h
|
|
@@ -104,3 +104,11 @@ free_stat_x(stat_x *sx_p)
|
|
}
|
|
#endif
|
|
}
|
|
+
|
|
+static inline char *my_strdup(const char *str, const char *file, int line)
|
|
+{
|
|
+ int len = strlen(str)+1;
|
|
+ char *buf = my_alloc(NULL, len, 1, file, line);
|
|
+ memcpy(buf, str, len);
|
|
+ return buf;
|
|
+}
|
|
\ No newline at end of file
|
|
Index: rsync-3.1.3/util2.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/util2.c
|
|
+++ rsync-3.1.3/util2.c
|
|
@@ -25,6 +25,9 @@
|
|
#include "itypes.h"
|
|
#include "inums.h"
|
|
|
|
+extern size_t max_alloc;
|
|
+
|
|
+char *do_calloc = "42";
|
|
/**
|
|
* Sleep for a specified number of milliseconds.
|
|
*
|
|
@@ -77,6 +80,26 @@ void *_realloc_array(void *ptr, unsigned
|
|
return realloc(ptr, size * num);
|
|
}
|
|
|
|
+void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line)
|
|
+{
|
|
+ if (max_alloc && num >= max_alloc/size) {
|
|
+ if (!file)
|
|
+ return NULL;
|
|
+ rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n",
|
|
+ who_am_i(), do_big_num(max_alloc, 0, NULL), src_file(file), line);
|
|
+ exit_cleanup(RERR_MALLOC);
|
|
+ }
|
|
+ if (!ptr)
|
|
+ ptr = malloc(num * size);
|
|
+ else if (ptr == do_calloc)
|
|
+ ptr = calloc(num, size);
|
|
+ else
|
|
+ ptr = realloc(ptr, num * size);
|
|
+ if (!ptr && file)
|
|
+ _out_of_memory("my_alloc caller", file, line);
|
|
+ return ptr;
|
|
+}
|
|
+
|
|
const char *sum_as_hex(int csum_type, const char *sum, int flist_csum)
|
|
{
|
|
static char buf[MAX_DIGEST_LEN*2+1];
|
|
@@ -99,6 +122,27 @@ const char *sum_as_hex(int csum_type, co
|
|
return buf;
|
|
}
|
|
|
|
+NORETURN void _out_of_memory(const char *msg, const char *file, int line)
|
|
+{
|
|
+ rprintf(FERROR, "[%s] out of memory: %s (file=%s, line=%d)\n", who_am_i(), msg, src_file(file), line);
|
|
+ exit_cleanup(RERR_MALLOC);
|
|
+}
|
|
+
|
|
+const char *src_file(const char *file)
|
|
+{
|
|
+ static const char *util2 = __FILE__;
|
|
+ static int prefix = -1;
|
|
+
|
|
+ if (prefix < 0) {
|
|
+ const char *cp = strrchr(util2, '/');
|
|
+ prefix = cp ? cp - util2 + 1 : 0;
|
|
+ }
|
|
+
|
|
+ if (prefix && strncmp(file, util2, prefix) == 0)
|
|
+ return file + prefix;
|
|
+ return file;
|
|
+}
|
|
+
|
|
NORETURN void out_of_memory(const char *str)
|
|
{
|
|
rprintf(FERROR, "ERROR: out of memory in %s [%s]\n", str, who_am_i());
|
|
Index: rsync-3.1.3/options.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/options.c
|
|
+++ rsync-3.1.3/options.c
|
|
@@ -185,6 +185,9 @@ int link_dest = 0;
|
|
int basis_dir_cnt = 0;
|
|
char *dest_option = NULL;
|
|
|
|
+#define DEFAULT_MAX_ALLOC (1024L * 1024 * 1024)
|
|
+size_t max_alloc = DEFAULT_MAX_ALLOC;
|
|
+
|
|
static int remote_option_alloc = 0;
|
|
int remote_option_cnt = 0;
|
|
const char **remote_options = NULL;
|
|
Index: rsync-3.1.3/Makefile.in
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/Makefile.in
|
|
+++ rsync-3.1.3/Makefile.in
|
|
@@ -46,7 +46,7 @@ popt_OBJS=popt/findme.o popt/popt.o po
|
|
popt/popthelp.o popt/poptparse.o
|
|
OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@
|
|
|
|
-TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
|
+TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@
|
|
|
|
# Programs we must have to run the test cases
|
|
CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \
|
|
@@ -128,7 +128,7 @@ getgroups$(EXEEXT): getgroups.o
|
|
getfsdev$(EXEEXT): getfsdev.o
|
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS)
|
|
|
|
-TRIMSLASH_OBJ = trimslash.o syscall.o lib/compat.o lib/snprintf.o
|
|
+TRIMSLASH_OBJ = trimslash.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o
|
|
trimslash$(EXEEXT): $(TRIMSLASH_OBJ)
|
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS)
|
|
|
|
Index: rsync-3.1.3/t_stub.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/t_stub.c
|
|
+++ rsync-3.1.3/t_stub.c
|
|
@@ -31,6 +31,7 @@ int module_dirlen = 0;
|
|
int preserve_acls = 0;
|
|
int preserve_times = 0;
|
|
int preserve_xattrs = 0;
|
|
+size_t max_alloc = 0; /* max_alloc is needed when combined with util2.o */
|
|
char *partial_dir;
|
|
char *module_dir;
|
|
filter_rule_list daemon_filter_list;
|
|
Index: rsync-3.1.3/tls.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/tls.c
|
|
+++ rsync-3.1.3/tls.c
|
|
@@ -51,8 +51,8 @@ int link_owner = 0;
|
|
int nsec_times = 0;
|
|
int preserve_perms = 0;
|
|
int preserve_executability = 0;
|
|
-int preallocate_files = 0;
|
|
-int inplace = 0;
|
|
+// int preallocate_files = 0;
|
|
+// int inplace = 0;
|
|
int noatime = 0;
|
|
|
|
#ifdef SUPPORT_XATTRS
|
|
Index: rsync-3.1.3/trimslash.c
|
|
===================================================================
|
|
--- rsync-3.1.3.orig/trimslash.c
|
|
+++ rsync-3.1.3/trimslash.c
|
|
@@ -28,8 +28,8 @@ int read_only = 1;
|
|
int list_only = 0;
|
|
int preserve_perms = 0;
|
|
int preserve_executability = 0;
|
|
-int preallocate_files = 0;
|
|
-int inplace = 0;
|
|
+// int preallocate_files = 0;
|
|
+// int inplace = 0;
|
|
int noatime = 0;
|
|
|
|
int
|