diff options
Diffstat (limited to 'debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0002-added-secure_relative_open.patch')
-rw-r--r-- | debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0002-added-secure_relative_open.patch | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0002-added-secure_relative_open.patch b/debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0002-added-secure_relative_open.patch new file mode 100644 index 0000000..719c6f1 --- /dev/null +++ b/debian/patches/rsync-upstream-CVE-patches-v3/CVE-2024-12086/0002-added-secure_relative_open.patch @@ -0,0 +1,103 @@ +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(+) + +diff --git a/syscall.c b/syscall.c +index d92074aa..a4b7f542 100644 +--- a/syscall.c ++++ b/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; +@@ -712,3 +714,75 @@ int do_open_nofollow(const char *pathname, int flags) + + 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 ++} +-- +2.34.1 + |