Skip to content

Commit

Permalink
fuzz: added fuzz test for listener filter tls_inspector (#12617)
Browse files Browse the repository at this point in the history
Created tls_inspector_corpus and populated with testcases (valid and invalid client hellos)

Risk Level: Low
Testing: increased function coverage of tls_inspector.cc to 100.0% and line coverage to 87.3% after running fuzzer (covers all parse states except errors related to socket read failure).
Docs Changes: N/A
Release Notes: N/A

Signed-off-by: Arthur Yan <arthuryan@google.com>
  • Loading branch information
arthuryan-k authored Aug 14, 2020
1 parent a42a677 commit 62f7d93
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void ListenerFilterFuzzer::fuzz(
while (!got_continue) {
if (header.done()) { // End of stream reached but not done
file_event_callback_(Event::FileReadyType::Closed);
return;
} else {
file_event_callback_(Event::FileReadyType::Read);
}
Expand All @@ -74,19 +75,19 @@ FuzzedHeader::FuzzedHeader(const test::extensions::filters::listener::FilterFuzz
len += input.data(i).size();
}

header_.reserve(len);
data_.reserve(len);

for (int i = 0; i < nreads_; i++) {
header_ += input.data(i);
indices_.push_back(header_.size());
data_.insert(data_.end(), input.data(i).begin(), input.data(i).end());
indices_.push_back(data_.size());
}
}

Api::SysCallSizeResult FuzzedHeader::next(void* buffer, size_t length) {
if (done()) { // End of stream reached
nread_ = nreads_ - 1; // Decrement to avoid out-of-range for last recv() call
}
memcpy(buffer, header_.data(), std::min(indices_[nread_], length));
memcpy(buffer, data_.data(), std::min(indices_[nread_], length));
return Api::SysCallSizeResult{static_cast<ssize_t>(indices_[nread_++]), 0};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class FuzzedHeader {
bool empty();

private:
const int nreads_; // Number of reads
int nread_; // Counter of current read
std::string header_; // Construct header from single or multiple reads
const int nreads_; // Number of reads
int nread_; // Counter of current read
std::vector<uint8_t> data_;
std::vector<size_t> indices_; // Ending indices for each read
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ message Socket {

message FilterFuzzTestCase {
Socket sock = 1;
repeated string data = 2;
repeated bytes data = 2;
}
21 changes: 21 additions & 0 deletions test/extensions/filters/listener/tls_inspector/BUILD
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_fuzz_test",
"envoy_cc_library",
"envoy_cc_test",
"envoy_package",
"envoy_proto_library",
)
load(
"//test/extensions:extensions_build_system.bzl",
Expand All @@ -29,6 +31,25 @@ envoy_cc_test(
],
)

envoy_proto_library(
name = "tls_inspector_fuzz_test_proto",
srcs = ["tls_inspector_fuzz_test.proto"],
deps = [
"//test/extensions/filters/listener/common/fuzz:listener_filter_fuzzer_proto",
],
)

envoy_cc_fuzz_test(
name = "tls_inspector_fuzz_test",
srcs = ["tls_inspector_fuzz_test.cc"],
corpus = "tls_inspector_corpus",
deps = [
":tls_inspector_fuzz_test_proto_cc_proto",
"//source/extensions/filters/listener/tls_inspector:tls_inspector_lib",
"//test/extensions/filters/listener/common/fuzz:listener_filter_fuzzer_lib",
],
)

envoy_extension_cc_benchmark_binary(
name = "tls_inspector_benchmark",
srcs = ["tls_inspector_benchmark.cc"],
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "extensions/filters/listener/tls_inspector/tls_inspector.h"

#include "test/extensions/filters/listener/common/fuzz/listener_filter_fuzzer.h"
#include "test/extensions/filters/listener/tls_inspector/tls_inspector_fuzz_test.pb.validate.h"
#include "test/fuzz/fuzz_runner.h"

namespace Envoy {
namespace Extensions {
namespace ListenerFilters {
namespace TlsInspector {

DEFINE_PROTO_FUZZER(
const test::extensions::filters::listener::tls_inspector::TlsInspectorTestCase& input) {

try {
TestUtility::validate(input);
} catch (const ProtoValidationException& e) {
ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what());
return;
}

Stats::IsolatedStoreImpl store;
ConfigSharedPtr cfg;

if (input.max_size() == 0) {
// If max_size not set, use default constructor
cfg = std::make_shared<Config>(store);
} else {
cfg = std::make_shared<Config>(store, input.max_size());
}

auto filter = std::make_unique<Filter>(cfg);

ListenerFilterFuzzer fuzzer;
fuzzer.fuzz(*filter, input.fuzzed());
}

} // namespace TlsInspector
} // namespace ListenerFilters
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
syntax = "proto3";

package test.extensions.filters.listener.tls_inspector;

import "test/extensions/filters/listener/common/fuzz/listener_filter_fuzzer.proto";
import "validate/validate.proto";

message TlsInspectorTestCase {
uint32 max_size = 1 [(validate.rules).uint32.lte = 65536];
test.extensions.filters.listener.FilterFuzzTestCase fuzzed = 2
[(validate.rules).message.required = true];
}

0 comments on commit 62f7d93

Please sign in to comment.