Jonathan Wright
7422694227
Fix for CVE-2024-12085 Fix for CVE-2024-12086 Fix for CVE-2024-12087 Fix for CVE-2024-12088 Fix for CVE-2024-12747
59 lines
2.1 KiB
Diff
59 lines
2.1 KiB
Diff
diff --git a/testsuite/unsafe-byname.test b/testsuite/unsafe-byname.test
|
|
index 75e7201..d2e318e 100644
|
|
--- a/testsuite/unsafe-byname.test
|
|
+++ b/testsuite/unsafe-byname.test
|
|
@@ -40,7 +40,7 @@ test_unsafe ..//../dest from/dir unsafe
|
|
test_unsafe .. from/file safe
|
|
test_unsafe ../.. from/file unsafe
|
|
test_unsafe ..//.. from//file unsafe
|
|
-test_unsafe dir/.. from safe
|
|
+test_unsafe dir/.. from unsafe
|
|
test_unsafe dir/../.. from unsafe
|
|
test_unsafe dir/..//.. from unsafe
|
|
|
|
diff --git a/util1.c b/util1.c
|
|
index da50ff1..f260d39 100644
|
|
--- a/util1.c
|
|
+++ b/util1.c
|
|
@@ -1318,7 +1318,14 @@ int handle_partial_dir(const char *fname, int create)
|
|
*
|
|
* "src" is the top source directory currently applicable at the level
|
|
* of the referenced symlink. This is usually the symlink's full path
|
|
- * (including its name), as referenced from the root of the transfer. */
|
|
+ * (including its name), as referenced from the root of the transfer.
|
|
+ *
|
|
+ * NOTE: this also rejects dest names with a .. component in other
|
|
+ * than the first component of the name ie. it rejects names such as
|
|
+ * a/b/../x/y. This needs to be done as the leading subpaths 'a' or
|
|
+ * 'b' could later be replaced with symlinks such as a link to '.'
|
|
+ * resulting in the link being transferred now becoming unsafe
|
|
+ */
|
|
int unsafe_symlink(const char *dest, const char *src)
|
|
{
|
|
const char *name, *slash;
|
|
@@ -1328,6 +1335,23 @@ int unsafe_symlink(const char *dest, const char *src)
|
|
if (!dest || !*dest || *dest == '/')
|
|
return 1;
|
|
|
|
+ // reject destinations with /../ in the name other than at the start of the name
|
|
+ const char *dest2 = dest;
|
|
+ while (strncmp(dest2, "../", 3) == 0) {
|
|
+ dest2 += 3;
|
|
+ while (*dest2 == '/') {
|
|
+ // allow for ..//..///../foo
|
|
+ dest2++;
|
|
+ }
|
|
+ }
|
|
+ if (strstr(dest2, "/../"))
|
|
+ return 1;
|
|
+
|
|
+ // reject if the destination ends in /..
|
|
+ const size_t dlen = strlen(dest);
|
|
+ if (dlen > 3 && strcmp(&dest[dlen-3], "/..") == 0)
|
|
+ return 1;
|
|
+
|
|
/* find out what our safety margin is */
|
|
for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
|
|
/* ".." segment starts the count over. "." segment is ignored. */
|
|
|