diff --git a/devel/fuzz_llvm_make_safe_uri.c b/devel/fuzz_llvm_make_safe_uri.c index a82de59..17fc800 100644 --- a/devel/fuzz_llvm_make_safe_uri.c +++ b/devel/fuzz_llvm_make_safe_uri.c @@ -116,20 +116,92 @@ static char *make_safe_url(char *url) { return url; } -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { +char *make_safe_url_new(char *const url) { + char *src = url, *dst; + #define ends(c) ((c) == '/' || (c) == '\0') + + /* URLs not starting with a slash are illegal. */ + if (*src != '/') + return NULL; + + /* Fast case: skip until first double-slash or dot-dir. */ + for ( ; *src && *src != '?'; ++src) { + if (*src == '/') { + if (src[1] == '/') + break; + else if (src[1] == '.') { + if (ends(src[2])) + break; + else if (src[2] == '.' && ends(src[3])) + break; + } + } + } + + /* Copy to dst, while collapsing multi-slashes and handling dot-dirs. */ + dst = src; + while (*src && *src != '?') { + if (*src != '/') + *dst++ = *src++; + else if (*++src == '/') + ; + else if (*src != '.') + *dst++ = '/'; + else if (ends(src[1])) + /* Ignore single-dot component. */ + ++src; + else if (src[1] == '.' && ends(src[2])) { + /* Double-dot component. */ + src += 2; + if (dst == url) + return NULL; /* Illegal URL */ + else + /* Backtrack to previous slash. */ + while (*--dst != '/' && dst > url); + } + else + *dst++ = '/'; + } + + if (dst == url) + ++dst; + *dst = '\0'; + return url; + #undef ends +} + +char* dup(const uint8_t *data, size_t size) { char *buf = malloc(size + 1); memcpy(buf, data, size); buf[size] = 0; + return buf; +} + +void check(char* safe) { + if (safe == NULL) return; + if (strstr(safe, "/../") != NULL) __builtin_trap(); + if (strstr(safe, "/./") != NULL) __builtin_trap(); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *buf1 = dup(data, size); + char *buf2 = dup(data, size); // Enable this to make sure the fuzzer is working. #if 0 - if (size > 2 && buf[2] == 'x') __builtin_trap(); + if (size > 2 && buf1[2] == 'x') __builtin_trap(); #endif - char *safe = make_safe_url(buf); - if (safe) { - if (strstr(safe, "/../") != NULL) __builtin_trap(); - if (strstr(safe, "/./") != NULL) __builtin_trap(); + char *safe1 = make_safe_url(buf1); + char *safe2 = make_safe_url(buf2); + check(safe1); + check(safe2); + if (safe1 == NULL) { + if (safe2 != NULL) __builtin_trap(); + } else { + if (strcmp(safe1, safe2) != 0) __builtin_trap(); } - free(buf); // Don't leak memory. + // Don't leak memory. + free(buf1); + free(buf2); return 0; }