92 lines
2.8 KiB
Diff
92 lines
2.8 KiB
Diff
From 535fa8d4deedc1da59884ce4f2fcc6528bf07251 Mon Sep 17 00:00:00 2001
|
|
From: Nathan Owens <ndowens04@gmail.com>
|
|
Date: Sat, 12 Jan 2019 22:29:49 -0600
|
|
Subject: [PATCH] CVE-2018-17828
|
|
|
|
---
|
|
bins/unzzipcat-big.c | 57 ++++++++++++++++++++++++++++++++++++++++++-
|
|
test/test.zip | Bin 1361 -> 0 bytes
|
|
2 files changed, 56 insertions(+), 1 deletion(-)
|
|
delete mode 100644 test/test.zip
|
|
|
|
diff --git bins/unzzipcat-big.c bins/unzzipcat-big.c
|
|
index 982d262..88c4d65 100644
|
|
--- bins/unzzipcat-big.c
|
|
+++ bins/unzzipcat-big.c
|
|
@@ -53,6 +53,48 @@ static void unzzip_cat_file(FILE* disk, char* name, FILE* out)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * NAME: remove_dotdotslash
|
|
+ * PURPOSE: To remove any "../" components from the given pathname
|
|
+ * ARGUMENTS: path: path name with maybe "../" components
|
|
+ * RETURNS: Nothing, "path" is modified in-place
|
|
+ * NOTE: removing "../" from the path ALWAYS shortens the path, never adds to it!
|
|
+ * Also, "path" is not used after creating it.
|
|
+ * So modifying "path" in-place is safe to do.
|
|
+ */
|
|
+static inline void
|
|
+remove_dotdotslash(char *path)
|
|
+{
|
|
+ /* Note: removing "../" from the path ALWAYS shortens the path, never adds to it! */
|
|
+ char *dotdotslash;
|
|
+ int warned = 0;
|
|
+
|
|
+ dotdotslash = path;
|
|
+ while ((dotdotslash = strstr(dotdotslash, "../")) != NULL)
|
|
+ {
|
|
+ /*
|
|
+ * Remove only if at the beginning of the pathname ("../path/name")
|
|
+ * or when preceded by a slash ("path/../name"),
|
|
+ * otherwise not ("path../name..")!
|
|
+ */
|
|
+ if (dotdotslash == path || dotdotslash[-1] == '/')
|
|
+ {
|
|
+ char *src, *dst;
|
|
+ if (!warned)
|
|
+ {
|
|
+ /* Note: the first time through the pathname is still intact */
|
|
+ fprintf(stderr, "Removing \"../\" path component(s) in %s\n", path);
|
|
+ warned = 1;
|
|
+ }
|
|
+ /* We cannot use strcpy(), as there "The strings may not overlap" */
|
|
+ for (src = dotdotslash+3, dst=dotdotslash; (*dst = *src) != '\0'; src++, dst++)
|
|
+ ;
|
|
+ }
|
|
+ else
|
|
+ dotdotslash +=3; /* skip this instance to prevent infinite loop */
|
|
+ }
|
|
+}
|
|
+
|
|
static void makedirs(const char* name)
|
|
{
|
|
char* p = strrchr(name, '/');
|
|
@@ -70,6 +112,16 @@ static void makedirs(const char* name)
|
|
|
|
static FILE* create_fopen(char* name, char* mode, int subdirs)
|
|
{
|
|
+ char *name_stripped;
|
|
+ FILE *fp;
|
|
+ int mustfree = 0;
|
|
+
|
|
+ if ((name_stripped = strdup(name)) != NULL)
|
|
+ {
|
|
+ remove_dotdotslash(name_stripped);
|
|
+ name = name_stripped;
|
|
+ mustfree = 1;
|
|
+ }
|
|
if (subdirs)
|
|
{
|
|
char* p = strrchr(name, '/');
|
|
@@ -79,7 +131,10 @@ static FILE* create_fopen(char* name, char* mode, int subdirs)
|
|
free (dir_name);
|
|
}
|
|
}
|
|
- return fopen(name, mode);
|
|
+ fp = fopen(name, mode);
|
|
+ if (mustfree)
|
|
+ free(name_stripped);
|
|
+ return fp;
|
|
}
|