Skip to content

Commit

Permalink
Try to fix #123 (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuba-- authored Mar 25, 2024
1 parent 31369ee commit 6f2116d
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 17 deletions.
46 changes: 29 additions & 17 deletions src/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,38 +248,50 @@ static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) {
return begin;
}

static inline int zip_strchr_match(const char *const str, size_t len, char c) {
size_t i;
for (i = 0; i < len; ++i) {
if (str[i] != c) {
return 0;
}
}

return 1;
}

static char *zip_name_normalize(char *name, char *const nname, size_t len) {
const char *const dot = ".\0";
const char *const dot2 = "..\0";
size_t offn = 0;
size_t offnn = 0, ncpy = 0;
size_t offn = 0, ncpy = 0;
char c;

if (name == NULL || nname == NULL || len <= 0) {
return NULL;
}
// skip trailing '/'
while (ISSLASH(*name))
while (ISSLASH(*name)) {
name++;
}

for (; offn < len; offn++) {
if (ISSLASH(name[offn])) {
if (ncpy > 0 && strcmp(&nname[offnn], dot) &&
strcmp(&nname[offnn], dot2)) {
offnn += ncpy;
nname[offnn++] = name[offn]; // append '/'
while ((c = *name++)) {
if (ISSLASH(c)) {
if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) {
offn += ncpy;
nname[offn++] = c; // append '/'
}
ncpy = 0;
} else {
nname[offnn + ncpy] = name[offn];
ncpy++;
nname[offn + ncpy] = c;
if (c) {
ncpy++;
}
}
}

// at the end, extra check what we've already copied
if (ncpy == 0 || !strcmp(&nname[offnn], dot) ||
!strcmp(&nname[offnn], dot2)) {
nname[offnn] = 0;
if (!zip_strchr_match(&nname[offn], ncpy, '.')) {
nname[offn + ncpy] = '\0';
} else {
nname[offn] = '\0';
}

return nname;
}

Expand Down
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ cmake_minimum_required(VERSION 3.14)
find_package(Sanitizers)

# tests
set(test_static_out test_static.out)
add_executable(${test_static_out} test_static.c)
add_test(NAME ${test_static_out} COMMAND ${test_static_out})
add_sanitizers(${test_static_out})

set(test_write_out test_write.out)
add_executable(${test_write_out} test_write.c)
target_link_libraries(${test_write_out} zip)
Expand Down
98 changes: 98 additions & 0 deletions test/test_static.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "minunit.h"

#ifndef ISSLASH
#define ISSLASH(C) ((C) == '/' || (C) == '\\')
#endif

static inline int zip_strchr_match(const char *const str, size_t len, char c) {
size_t i;
for (i = 0; i < len; ++i) {
if (str[i] != c) {
return 0;
}
}

return 1;
}

static char *zip_name_normalize(char *name, char *const nname, size_t len) {
size_t offn = 0, ncpy = 0;
char c;

if (name == NULL || nname == NULL || len <= 0) {
return NULL;
}
// skip trailing '/'
while (ISSLASH(*name)) {
name++;
}

while ((c = *name++)) {
if (ISSLASH(c)) {
if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) {
offn += ncpy;
nname[offn++] = c; // append '/'
}
ncpy = 0;
} else {
nname[offn + ncpy] = c;
if (c) {
ncpy++;
}
}
}

if (!zip_strchr_match(&nname[offn], ncpy, '.')) {
nname[offn + ncpy] = '\0';
} else {
nname[offn] = '\0';
}

return nname;
}

void test_setup(void) {}

void test_teardown(void) {}

MU_TEST(test_normalize) {
char nname[512] = {0};
char *name =
"/../../../../../../../../../../../../../../../../../../../../../../../"
"../../../../../../../../../../../../../../../../../tmp/evil.txt";
size_t len = strlen(name);
mu_assert_int_eq(
0, strcmp(zip_name_normalize(name, nname, len), "tmp/evil.txt\0"));

name = "../.ala/ala/...c.../../";
len = strlen(name);
mu_assert_int_eq(
0, strcmp(zip_name_normalize(name, nname, len), ".ala/ala/...c.../\0"));

name = "../evil.txt/.al";
len = strlen(name);
mu_assert_int_eq(
0, strcmp(zip_name_normalize(name, nname, len), "evil.txt/.al\0"));

name = "/.././.../a..../..../..a./.aaaa";
len = strlen(name);
mu_assert_int_eq(
0, strcmp(zip_name_normalize(name, nname, len), "a..../..a./.aaaa\0"));
}

MU_TEST_SUITE(test_static_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);

MU_RUN_TEST(test_normalize);
}

#define UNUSED(x) (void)x

int main(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);

MU_RUN_SUITE(test_static_suite);
MU_REPORT();
return MU_EXIT_CODE;
}

0 comments on commit 6f2116d

Please sign in to comment.