Skip to content

Commit

Permalink
fuzz: bare bones HCM fuzzer. (envoyproxy#4118)
Browse files Browse the repository at this point in the history
See caveats at the top of conn_manager_impl_fuzz_test.cc. HCM might not be the best place to be
investing fuzzing effort, would like to see if a basic fuzzer can provide some win before investing
more time in modeling HCM internals and building a corpus.

Risk level: Low
Testing: Supplied corpus has 56.7% coverage.

Signed-off-by: Harvey Tuch <htuch@google.com>
  • Loading branch information
htuch committed Aug 15, 2018
1 parent 73bd3d9 commit 592775b
Show file tree
Hide file tree
Showing 7 changed files with 688 additions and 0 deletions.
34 changes: 34 additions & 0 deletions test/common/http/BUILD
Expand Up @@ -91,6 +91,40 @@ envoy_cc_test_library(
],
)

envoy_proto_library(
name = "conn_manager_impl_fuzz_proto",
srcs = ["conn_manager_impl_fuzz.proto"],
external_deps = ["well_known_protos"],
generate_python = 0,
deps = [
"//test/fuzz:common_proto",
],
)

envoy_cc_fuzz_test(
name = "conn_manager_impl_fuzz_test",
srcs = ["conn_manager_impl_fuzz_test.cc"],
corpus = "conn_manager_impl_corpus",
deps = [
":conn_manager_impl_fuzz_proto",
"//source/common/common:empty_string",
"//source/common/http:conn_manager_lib",
"//source/common/http:date_provider_lib",
"//source/common/network:address_lib",
"//source/common/network:utility_lib",
"//test/fuzz:utility_lib",
"//test/mocks/access_log:access_log_mocks",
"//test/mocks/http:http_mocks",
"//test/mocks/local_info:local_info_mocks",
"//test/mocks/network:network_mocks",
"//test/mocks/runtime:runtime_mocks",
"//test/mocks/ssl:ssl_mocks",
"//test/mocks/tracing:tracing_mocks",
"//test/mocks/upstream:upstream_mocks",
"@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc",
],
)

envoy_cc_test(
name = "conn_manager_impl_test",
srcs = ["conn_manager_impl_test.cc"],
Expand Down
18 changes: 18 additions & 0 deletions test/common/http/conn_manager_impl_corpus/codec_exception
@@ -0,0 +1,18 @@
actions {
new_stream {
request_headers {
headers {
key: "foo"
value: "bar"
}
}
}
}
actions {
stream_action {
stream_id: 0
request {
throw_decoder_exception {}
}
}
}
Empty file.
120 changes: 120 additions & 0 deletions test/common/http/conn_manager_impl_corpus/example
@@ -0,0 +1,120 @@
actions {
new_stream {
request_headers {
headers {
key: ":method"
value: "GET"
}
headers {
key: ":path"
value: "/"
}
headers {
key: ":scheme"
value: "http"
}
headers {
key: ":authority"
value: "foo.com"
}
headers {
key: "blah"
value: "nosniff"
}
headers {
key: "cookie"
value: "foo=bar"
}
headers {
key: "cookie"
value: "foo2=bar2"
}
}
}
}
actions {
stream_action {
stream_id: 0
request {
data {
size: 3000000
decoder_filter_callback_action {
add_decoded_data {
size: 1000000
}
}
status: DATA_STOP_ITERATION_AND_BUFFER
}
}
}
}
actions {
stream_action {
stream_id: 0
request {
continue_decoding {}
}
}
}
actions {
stream_action {
stream_id: 0
response {
continue_100_headers {}
}
}
}
actions {
stream_action {
stream_id: 0
response {
headers {
headers {
key: ":status"
value: "200"
}
}
}
}
}
actions {
stream_action {
stream_id: 0
response {
data: 5
}
}
}
actions {
stream_action {
stream_id: 0
request {
trailers {
headers {
headers {
key: "foo"
value: "bar"
}
}
decoder_filter_callback_action {
add_decoded_data {
size: 1000000
}
}
}
}
}
}
actions {
stream_action {
stream_id: 0
response {
trailers {
headers {
key: "foo"
value: "bar"
}
}
}
}
}
10 changes: 10 additions & 0 deletions test/common/http/conn_manager_impl_corpus/missing_host
@@ -0,0 +1,10 @@
actions {
new_stream {
request_headers {
headers {
key: "foo"
value: "bar"
}
}
}
}
97 changes: 97 additions & 0 deletions test/common/http/conn_manager_impl_fuzz.proto
@@ -0,0 +1,97 @@
syntax = "proto3";

package test.common.http;

import "google/protobuf/empty.proto";

import "test/fuzz/common.proto";

// Structured input for conn_manager_impl_fuzz_test.

message NewStream {
test.fuzz.Headers request_headers = 1;
bool end_stream = 2;
// TODO(htuch): Support stop/continue status with headers.
}

enum HeaderStatus {
HEADER_CONTINUE = 0;
HEADER_STOP_ITERATION = 1;
}

enum DataStatus {
DATA_CONTINUE = 0;
DATA_STOP_ITERATION_AND_BUFFER = 1;
DATA_STOP_ITERATION_AND_WATERMARK = 2;
DATA_STOP_ITERATION_NO_BUFFER = 3;
}

enum TrailerStatus {
TRAILER_CONTINUE = 0;
TRAILER_STOP_ITERATION = 1;
}

message DecoderFilterCallbackAction {
message AddDecodedData {
uint32 size = 1;
bool streaming = 2;
}
oneof decoder_filter_callback_action_selector {
// TODO(htuch): More decoder filer callback actions
AddDecodedData add_decoded_data = 1;
}
}

message RequestAction {
message DataAction {
uint32 size = 1;
bool end_stream = 2;
DataStatus status = 3;
DecoderFilterCallbackAction decoder_filter_callback_action = 4;
}
message TrailerAction {
test.fuzz.Headers headers = 1;
TrailerStatus status = 2;
DecoderFilterCallbackAction decoder_filter_callback_action = 3;
}
oneof request_action_selector {
DataAction data = 1;
TrailerAction trailers = 2;
google.protobuf.Empty continue_decoding = 3;
google.protobuf.Empty throw_decoder_exception = 4;
// TODO(htuch): Model and fuzz watermark events.
}
}

// TODO(htuch): Model and fuzz encoder filter buffering/resumption and different status returns.
message ResponseAction {
oneof response_action_selector {
test.fuzz.Headers continue_100_headers = 1;
test.fuzz.Headers headers = 2;
uint32 data = 3;
test.fuzz.Headers trailers = 4;
// TODO(htuch): Model and fuzz watermark events.
}
bool end_stream = 7;
}

message StreamAction {
uint32 stream_id = 1;
oneof stream_action_selector {
RequestAction request = 2;
ResponseAction response = 3;
}
}

message Action {
oneof action_selector {
// Create new stream.
NewStream new_stream = 1;
// Perform an action on an existing stream.
StreamAction stream_action = 2;
}
}

message ConnManagerImplTestCase {
repeated Action actions = 1;
}

0 comments on commit 592775b

Please sign in to comment.