Skip to content

Commit

Permalink
Fixes skupperproject#1702: add fuzz testing of the http1 decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
kgiusti committed Dec 19, 2024
1 parent f2b8092 commit 2b8b154
Show file tree
Hide file tree
Showing 612 changed files with 93,995 additions and 16 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@
<exclude>scripts/git-clang-format</exclude>
<exclude>tests/nginx/**</exclude>
<exclude>tests/fuzz/fuzz_http2_decoder/**</exclude>
<exclude>tests/fuzz/fuzz_http1_decoder/**</exclude>
<exclude>tests/fuzz/fuzz_http1_request_decoder/**</exclude>
<exclude>tests/fuzz/fuzz_http1_response_decoder/**</exclude>
<exclude>**/README.md</exclude>
</excludes>
</configuration>
Expand Down
3 changes: 2 additions & 1 deletion tests/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ macro(add_fuzz_test test)
endmacro(add_fuzz_test test)

add_fuzz_test(fuzz_http2_decoder fuzz_http2_decoder.c)
#add_fuzz_test(fuzz_http1_decoder fuzz_http1_decoder.c)
add_fuzz_test(fuzz_http1_request_decoder fuzz_http1_request_decoder.c)
add_fuzz_test(fuzz_http1_response_decoder fuzz_http1_response_decoder.c)
25 changes: 18 additions & 7 deletions tests/fuzz/Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ WORKDIR /src/qpid-proton
RUN mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF -DENABLE_LINKTIME_OPTIMIZATION=OFF -DBUILD_TLS=ON -DSSL_IMPL=openssl -DBUILD_TOOLS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF && make install

WORKDIR /src
RUN git clone https://github.com/skupperproject/skupper-router.git
RUN git clone --depth 1 https://github.com/skupperproject/skupper-router.git

WORKDIR /src/skupper-router

Expand All @@ -49,12 +49,23 @@ RUN mkdir build
WORKDIR /src/skupper-router/build
RUN FUZZING_LANGUAGE='' FUZZING_ENGINE=afl /usr/local/bin/compile
WORKDIR /src/skupper-router/build/
RUN make install
RUN make -k install

# Attach to the container and run one of the following commands to run
# the http1 or http2 fuzzer. These commands start the AFL fuzzer which
# runs in an infinite loop. Let it run for about 30 minutes and press
# Ctrl + C to kill it. The AFL program displays the stats on stdout
# upon termination. Note that http1 has two separate fuzzers: one for
# request messages and one for response messages. This is necessary
# because http1 message formats are different for request and response
# messages.

#LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http1_request_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http1_request_decoder
#LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http1_response_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http1_response_decoder
#LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http2_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http2_decoder

# For the above commands the fuzzer will put the generated output in
# the /src/skupper-router/build/findings_dir directory.

# Run one of the following commands to run the http1 or http2 fuzzer.
# Starts the AFL fuzzer that runs in an infinite loop. Let it run for about 30 minutes and press Ctrl + C to kill it.
# The AFL program displays the stats on stdout upon termination.
#LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http1_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http1_decoder; fi
#LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http2_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http2_decoder; fi
CMD ["/bin/bash"]

9 changes: 9 additions & 0 deletions tests/fuzz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ The corpus files used by the regression tests are generated by running the fuzze
skupper-router/tests/fuzzContainerfile creates an environment where you can run the fuzzer of your choice. You will need to have seed corpus files which the fuzzer will use and build upon to create numerous additional corpus files.
If the code crashes, the input that led to the crash is saved. The crash files and the corpus files are downloaded from the container and used in regression testing.

By default the Containerfile clones skupper-router from its github repository. If you are working in your own git repo you will have to modify the _git clone_ command in the Containerfile to use your git repo and branch. For example:

```
# RUN git clone --depth 1 https://github.com/skupperproject/skupper-router.git
RUN git clone --depth 1 --branch my-branch https://github.com/myrepo/skupper-router.git
```

## Building and running Containerfile
To build the Containerfile from the skupper-router/tests/fuzz/folder<br/>
```
Expand All @@ -39,5 +46,7 @@ Once you are inside the container, run the AFL fuzzer as seen in the commented E
```
LD_LIBRARY_PATH=/usr/local/lib/clang/18/lib/x86_64-unknown-linux-gnu/ AFL_MAP_SIZE=10000000 AFL_DEBUG=1 AFL_SKIP_CPUFREQ=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 afl-fuzz -i /src/skupper-router/tests/fuzz/fuzz_http2_decoder/corpus/ -o findings_dir /src/skupper-router/build/tests/fuzz/fuzz_http2_decoder
```
See the comments in the Containerfile for more examples.<br/>

Let the fuzzer run for about an hour. Since the fuzzer runs infinitely, to stop the fuzzer, press Ctrl + C. Check for the findings_dir for crashes and additional corpus files. Download the crash and corpus files from the container and run them locally against your code to help fix the crashes.

113 changes: 113 additions & 0 deletions tests/fuzz/fuzz_http1_request_decoder.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#include <qpid/dispatch/alloc_pool.h>

#include "decoders/http1/http1_decoder.h"
#include "qpid/dispatch/ctools.h"

#include "libFuzzingEngine.h"

void qd_log_initialize(void);
void qd_error_initialize(void);
void qd_router_id_finalize(void);
void qd_log_finalize(void);

/**
* This function is processed on exit
*/
void call_on_exit(void)
{
qd_log_finalize();
qd_alloc_finalize();
qd_router_id_finalize();
}

int LLVMFuzzerInitialize(int *argc, char ***argv)
{
atexit(call_on_exit);

qd_alloc_initialize();
qd_log_initialize();
qd_error_initialize();
return 0;
}

//
// Dummy callbacks for the decoder.
//

static int _rx_request(qd_http1_decoder_connection_t *hconn,
const char *method,
const char *target,
uint32_t version_major,
uint32_t version_minor,
uintptr_t *request_context)
{
*request_context = 1;
return 0;
}

static int _rx_response(qd_http1_decoder_connection_t *hconn, uintptr_t request_context,
int status_code,
const char *reason_phrase,
uint32_t version_major,
uint32_t version_minor)
{ return 0; }

static int _rx_header(qd_http1_decoder_connection_t *hconn, uintptr_t request_context, bool from_client,
const char *key, const char *value)
{ return 0; }

static int _rx_headers_done(qd_http1_decoder_connection_t *hconn, uintptr_t request_context, bool from_client)
{ return 0; }

static int _rx_body(qd_http1_decoder_connection_t *hconn, uintptr_t request_context, bool from_client, const unsigned char *body, size_t length)
{ return 0; }

static int _message_done(qd_http1_decoder_connection_t *hconn, uintptr_t request_context, bool from_client)
{ return 0; }

static int _transaction_complete(qd_http1_decoder_connection_t *hconn, uintptr_t request_context)
{ return 0; }

static void _protocol_error(qd_http1_decoder_connection_t *hconn, const char *reason)
{ }


const struct qd_http1_decoder_config_t test_config = {
.rx_request = _rx_request,
.rx_response = _rx_response,
.rx_header = _rx_header,
.rx_headers_done = _rx_headers_done,
.rx_body = _rx_body,
.message_done = _message_done,
.transaction_complete = _transaction_complete,
.protocol_error = _protocol_error
};


int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
qd_http1_decoder_connection_t *conn_state = qd_http1_decoder_connection(&test_config, 1);
qd_http1_decoder_connection_rx_data(conn_state, true, (const unsigned char *) data, size);
qd_http1_decoder_connection_free(conn_state);
return 0;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GET https://host.com/url/path?query HTTP/1.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
POST /sorl HTTP/1.1
dumr: hi
content-length: 5

12345
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
POST /anl HTTP/1.1
transfer-encoding: a,b,chunked

03
ABC
00

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET /pipeline/1 HTTP/1.1
Content-length: 0

GET //2 HTTP/1.1
content-length: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GET e/1 HTP/1.1
Co
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET eline/1 HTTP/1.1
Content-length: 0

GET //2 H
A
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�T
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GET /pipeline/1 HTTP/1.1
TTer: hi
ngth: 1
c11.ontent-length: 1

A
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET eline/1 HTTP/1.1
Co1.1
content-length: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GET /pi: 1nt-lTP/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GET /pi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
















Gne/1 HTTP/1.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GETTP/1.1
T
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GET eline/1 HTTP/1.1
Content-length: 0

GET //2 HTTP/1.1
content-length: 1
A
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GDT /pi�
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GET eline/1 HTTP/1.1
Content-length: 0

Gt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET eline/1 HTTP/1.1
Content-length: 0

GET //2 HTTP/1.1
coigth: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GE�
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET eline/1 HTTP/1.1
Content-length: 0
.1
con
GET /�
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GET eline/1 HTTP/1.1
Content-length:0

G
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GET e/1 HTTP/1.1
CotleTP/1.1ngth: 0
G
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET line/1 HTTP/1.1
Congth: 0

GET //2 HTTP/1.1
th:::::::::::::::: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET eline/1 HTTP/1.1
Cn: 0

GET //2 HTTP/1.1
content-length: 5

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GET eline/1 HTTP/1.1
CT.1
1
c1.1
ct-gth: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
GET eline/1 HTTP/1.1
Content-length:1
0

GET //2 HTTP/1.1
content-length: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
GET eline/1 HTTP/1.1
Content-length: 0

pET //o HTTP/1.1
con
.1h: 1

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GE e/1 HTTP/1.1
eline1.1


GETea

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
T O/e/1 HTTP/1.1
CongtttttttHTTP/1.1
Ce
0'
//

A
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
GET eline/1 HTTP/1.1
Content-length: 0

GET //2 HTTP/1.1
congt1:.1
th: 0

GET 1
Loading

0 comments on commit 2b8b154

Please sign in to comment.