diff --git a/fuzz/fuzz_frames.cc b/fuzz/fuzz_frames.cc new file mode 100644 index 00000000..511625ff --- /dev/null +++ b/fuzz/fuzz_frames.cc @@ -0,0 +1,161 @@ +#include +#include + +extern "C" { +#include +#include "nghttp2_hd.h" +#include "nghttp2_frame.h" + +#include "nghttp2_test_helper.h" + +#define HEADERS_LENGTH 7 + +static nghttp2_nv fuzz_make_nv(std::string s1, std::string s2) { + nghttp2_nv nv; + uint8_t *n = (uint8_t*) malloc(s1.size()); + memcpy(n, s1.c_str(), s1.size()); + + uint8_t *v = (uint8_t*) malloc(s2.size()); + memcpy(v, s2.c_str(), s2.size()); + + nv.name = n; + nv.value = v; + nv.namelen = s1.size(); + nv.valuelen = s2.size(); + nv.flags = NGHTTP2_NV_FLAG_NONE; + + return nv; +} + +static void fuzz_free_nv(nghttp2_nv *nv) { + free(nv->name); + free(nv->value); +} + +void check_frame_pack_headers(FuzzedDataProvider* data_provider) { + nghttp2_hd_deflater deflater; + nghttp2_hd_inflater inflater; + nghttp2_headers frame, oframe; + nghttp2_bufs bufs; + nghttp2_nv *nva; + nghttp2_priority_spec pri_spec; + size_t nvlen; + nva_out out; + size_t hdblocklen; + int rv; + nghttp2_mem *mem; + + mem = nghttp2_mem_default(); + frame_pack_bufs_init(&bufs); + + nva_out_init(&out); + nghttp2_hd_deflate_init(&deflater, mem); + nghttp2_hd_inflate_init(&inflater, mem); + + /* Create a set of headers seeded with data from the fuzzer */ + nva = (nghttp2_nv *)mem->malloc(sizeof(nghttp2_nv) * HEADERS_LENGTH, NULL); + for (int i = 0; i < HEADERS_LENGTH; i++) { + nva[i] = fuzz_make_nv(data_provider->ConsumeRandomLengthString(30), + data_provider->ConsumeRandomLengthString(300)); + } + + nvlen = HEADERS_LENGTH; + nghttp2_priority_spec_default_init(&pri_spec); + nghttp2_frame_headers_init( + &frame, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, 1000000007, + NGHTTP2_HCAT_REQUEST, &pri_spec, nva, nvlen); + + /* Perform a set of operations with the fuzz data */ + rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); + if (rv == 0) { + unpack_framebuf((nghttp2_frame *)&oframe, &bufs); + + inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN, mem); + nva_out_reset(&out, mem); + nghttp2_bufs_reset(&bufs); + } + + nghttp2_nv *nva2 = NULL; + rv = nghttp2_nv_array_copy(&nva2, nva, nvlen, mem); + if (rv == 0) { + nghttp2_nv_array_del(nva2, mem); + } + + /* Cleanup */ + for (int i = 0; i < HEADERS_LENGTH; i++) { + fuzz_free_nv(&nva[i]); + } + + nghttp2_bufs_free(&bufs); + nghttp2_frame_headers_free(&frame, mem); + nghttp2_hd_inflate_free(&inflater); + nghttp2_hd_deflate_free(&deflater); +} + +void check_frame_push_promise(FuzzedDataProvider* data_provider) { + nghttp2_hd_deflater deflater; + nghttp2_hd_inflater inflater; + nghttp2_push_promise frame, oframe; + nghttp2_bufs bufs; + nghttp2_nv *nva; + nghttp2_priority_spec pri_spec; + size_t nvlen; + nva_out out; + size_t hdblocklen; + int rv; + nghttp2_mem *mem; + + mem = nghttp2_mem_default(); + frame_pack_bufs_init(&bufs); + + nva_out_init(&out); + nghttp2_hd_deflate_init(&deflater, mem); + nghttp2_hd_inflate_init(&inflater, mem); + + /* Create a set of headers seeded with data from the fuzzer */ + nva = (nghttp2_nv *)mem->malloc(sizeof(nghttp2_nv) * HEADERS_LENGTH, NULL); + for (int i = 0; i < HEADERS_LENGTH; i++) { + nva[i] = fuzz_make_nv(data_provider->ConsumeRandomLengthString(30), + data_provider->ConsumeRandomLengthString(300)); + } + nvlen = HEADERS_LENGTH; + nghttp2_priority_spec_default_init(&pri_spec); + + /* Perform a set of operations with the fuzz data */ + nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_HEADERS, 1000000007, + (1U << 31) - 1, nva, nvlen); + + rv = nghttp2_frame_pack_push_promise(&bufs, &frame, &deflater); + if (rv == 0) { + unpack_framebuf((nghttp2_frame *)&oframe, &bufs); + } + + nghttp2_nv *nva2 = NULL; + rv = nghttp2_nv_array_copy(&nva2, nva, nvlen, mem); + if (rv == 0) { + nghttp2_nv_array_del(nva2, mem); + } + + /* Cleanup */ + for (int i = 0; i < HEADERS_LENGTH; i++) { + fuzz_free_nv(&nva[i]); + } + + nghttp2_bufs_reset(&bufs); + nghttp2_bufs_free(&bufs); + + nghttp2_frame_push_promise_free(&frame, mem); + nghttp2_hd_inflate_free(&inflater); + nghttp2_hd_deflate_free(&deflater); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FuzzedDataProvider data_provider(data, size); + + check_frame_pack_headers(&data_provider); + check_frame_push_promise(&data_provider); + return 0; +} + +} // extern C +