From patchwork Mon Oct 12 12:37:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Petr_=C5=A0tetiar?= X-Patchwork-Id: 1380880 X-Patchwork-Delegate: ynezz@true.cz Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.openwrt.org (client-ip=2001:8b0:10b:1231::1; helo=merlin.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=true.cz Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=merlin.20170209 header.b=CRmk9YT1; dkim-atps=neutral Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:8b0:10b:1231::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4C8ytK1N2Yz9sVJ for ; Mon, 12 Oct 2020 23:39:36 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=KLcs2Dx3a+PtnguXO4KpKWhOBBwzcvny3A1y0TNlkC8=; b=CRmk9YT1tyLwsNkGz8nQYpA9k jM/88haZdm5EJu+WX7L89eiBLXBaknUCYnuLy9T4RXro4IJfPdpp92PUngQtphDKrVflYOiEjTrgI nNunhto/WYYu4GroJ3KqgP5kjBBJ6qoIevZAwy38glIlQa+ylI5v65JxqkPkBWcFjTtE2X45ph9Ml qXcwoyQrPT8lkbvKi/7O/irxG1Nh0PJR2MPBBRkjalBsu/E9KJxcePhxfmembC0obohMJRZyrzib1 2IflJBGjN6z/u97MBg67IVPYXRrXxcYP9Wk6F0oI0JJc/Q2MqdtT7usp+YJpi7cbdvG9YhsqeoZMN dXFuXSsFw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kRx5L-0002t6-7p; Mon, 12 Oct 2020 12:37:51 +0000 Received: from smtp-out.xnet.cz ([178.217.244.18]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kRx51-0002nO-H2 for openwrt-devel@lists.openwrt.org; Mon, 12 Oct 2020 12:37:35 +0000 Received: from meh.true.cz (meh.true.cz [108.61.167.218]) (Authenticated sender: petr@true.cz) by smtp-out.xnet.cz (Postfix) with ESMTPSA id 1E9EB35E1; Mon, 12 Oct 2020 14:37:27 +0200 (CEST) Received: by meh.true.cz (OpenSMTPD) with ESMTP id 0bf32bfc; Mon, 12 Oct 2020 14:37:10 +0200 (CEST) From: =?utf-8?q?Petr_=C5=A0tetiar?= To: openwrt-devel@lists.openwrt.org Subject: [PATCH cgi-io 06/12] Add fuzzing of utility functions Date: Mon, 12 Oct 2020 14:37:12 +0200 Message-Id: <20201012123718.25623-7-ynezz@true.cz> In-Reply-To: <20201012123718.25623-1-ynezz@true.cz> References: <20201012123718.25623-1-ynezz@true.cz> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201012_083731_730812_71742CC3 X-CRM114-Status: GOOD ( 27.26 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 SPF_NONE SPF: sender does not publish an SPF Record X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Petr_=C5=A0tetiar?= Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Thus increase fuzzing coverage. Signed-off-by: Petr Štetiar --- tests/CMakeLists.txt | 1 + tests/fuzz/CMakeLists.txt | 18 ++++ .../58668e7669fd564d99db5d581fcdb6a5618440b5 | 1 + .../5ba93c9db0cff93f52b521d7420e43f6eda2784f | Bin 0 -> 1 bytes .../adc83b19e793491b1c6ea0fd8b46cd9f32e592fc | 1 + tests/fuzz/test-fuzz.c | 43 +++++++++ util.c | 84 ++++++++++-------- util.h | 1 + 8 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 tests/fuzz/CMakeLists.txt create mode 100644 tests/fuzz/corpus/58668e7669fd564d99db5d581fcdb6a5618440b5 create mode 100644 tests/fuzz/corpus/5ba93c9db0cff93f52b521d7420e43f6eda2784f create mode 100644 tests/fuzz/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc create mode 100644 tests/fuzz/test-fuzz.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8bb2a59412da..efad20642dd6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,4 @@ IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + ADD_SUBDIRECTORY(fuzz) ADD_SUBDIRECTORY(fuzz-multipart-parser) ENDIF() diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt new file mode 100644 index 000000000000..b4df45ca7b9b --- /dev/null +++ b/tests/fuzz/CMakeLists.txt @@ -0,0 +1,18 @@ +FILE(GLOB test_cases "test-*.c") + +MACRO(ADD_FUZZER_TEST name) + ADD_EXECUTABLE(${name} ${name}.c) + TARGET_COMPILE_OPTIONS(${name} PRIVATE -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address,leak,undefined) + TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR}) + TARGET_LINK_OPTIONS(${name} PRIVATE -stdlib=libc++ -fsanitize=fuzzer,address,leak,undefined) + TARGET_LINK_LIBRARIES(${name} cgi-lib) + ADD_TEST( + NAME ${name} + COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 ${CMAKE_CURRENT_SOURCE_DIR}/corpus + ) +ENDMACRO(ADD_FUZZER_TEST) + +FOREACH(test_case ${test_cases}) + GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE) + ADD_FUZZER_TEST(${test_case}) +ENDFOREACH(test_case) diff --git a/tests/fuzz/corpus/58668e7669fd564d99db5d581fcdb6a5618440b5 b/tests/fuzz/corpus/58668e7669fd564d99db5d581fcdb6a5618440b5 new file mode 100644 index 000000000000..22aac29bb31b --- /dev/null +++ b/tests/fuzz/corpus/58668e7669fd564d99db5d581fcdb6a5618440b5 @@ -0,0 +1 @@ +J \ No newline at end of file diff --git a/tests/fuzz/corpus/5ba93c9db0cff93f52b521d7420e43f6eda2784f b/tests/fuzz/corpus/5ba93c9db0cff93f52b521d7420e43f6eda2784f new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/tests/fuzz/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc b/tests/fuzz/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/fuzz/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc @@ -0,0 +1 @@ + diff --git a/tests/fuzz/test-fuzz.c b/tests/fuzz/test-fuzz.c new file mode 100644 index 000000000000..a62c32609979 --- /dev/null +++ b/tests/fuzz/test-fuzz.c @@ -0,0 +1,43 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "util.h" + +static void fuzz_parse_command(const char *buf) +{ + char **p = parse_command(buf); + if (p) + free(p); +} + +int LLVMFuzzerTestOneInput(const uint8_t *input, size_t size) +{ + char *p = NULL; + char *fields[] = { "sessionid", NULL, "path", NULL, "filename", NULL, "mimetype", NULL }; + char *buf = calloc(1, size+1); + memcpy(buf, input, size); + + urldecode(buf); + fuzz_parse_command(buf); + p = canonicalize_path(buf, size+1); + if (p) + free(p); + + p = postdecode_fields(buf, size+1, fields, 4); + if (!p) + return 0; + + free(buf); + + return 0; +} diff --git a/util.c b/util.c index 9eb7b485e5fa..e8627589b49a 100644 --- a/util.c +++ b/util.c @@ -5,6 +5,8 @@ #include #include +#include + #include "util.h" char ** @@ -80,12 +82,55 @@ parse_command(const char *cmdline) return argv; } +char * +postdecode_fields(char *postbuf, ssize_t len, char **fields, int n_fields) +{ + char *p; + int i, field, found = 0; + + for (p = postbuf, i = 0; i <= len; i++) + { + if (postbuf[i] == '=') + { + postbuf[i] = 0; + + for (field = 0; field < (n_fields * 2); field += 2) + { + if (!strcmp(p, fields[field])) + { + fields[field + 1] = postbuf + i + 1; + found++; + } + } + } + else if (postbuf[i] == '&' || postbuf[i] == '\0') + { + postbuf[i] = 0; + + if (found >= n_fields) + break; + + p = postbuf + i + 1; + } + } + + for (field = 0; field < (n_fields * 2); field += 2) + { + if (!urldecode(fields[field + 1])) + { + free(postbuf); + return NULL; + } + } + + return postbuf; +} + char * postdecode(char **fields, int n_fields) { const char *var; char *p, *postbuf; - int i, field, found = 0; ssize_t len = 0, rlen = 0, content_length = 0; var = getenv("CONTENT_TYPE"); @@ -124,42 +169,7 @@ postdecode(char **fields, int n_fields) return NULL; } - for (p = postbuf, i = 0; i <= len; i++) - { - if (postbuf[i] == '=') - { - postbuf[i] = 0; - - for (field = 0; field < (n_fields * 2); field += 2) - { - if (!strcmp(p, fields[field])) - { - fields[field + 1] = postbuf + i + 1; - found++; - } - } - } - else if (postbuf[i] == '&' || postbuf[i] == '\0') - { - postbuf[i] = 0; - - if (found >= n_fields) - break; - - p = postbuf + i + 1; - } - } - - for (field = 0; field < (n_fields * 2); field += 2) - { - if (!urldecode(fields[field + 1])) - { - free(postbuf); - return NULL; - } - } - - return postbuf; + return postdecode_fields(postbuf, len, fields, n_fields); } char * diff --git a/util.h b/util.h index 0001195df38a..ecffe6c2bd73 100644 --- a/util.h +++ b/util.h @@ -6,6 +6,7 @@ char** parse_command(const char *cmdline); char* postdecode(char **fields, int n_fields); +char* postdecode_fields(char *postbuf, ssize_t len, char **fields, int n_fields); char* canonicalize_path(const char *path, size_t len); bool urldecode(char *buf); char* datadup(const void *in, size_t len);