Skip to content

Commit 592775b

Browse files
authored
fuzz: bare bones HCM fuzzer. (#4118)
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>
1 parent 73bd3d9 commit 592775b

7 files changed

Lines changed: 688 additions & 0 deletions

File tree

test/common/http/BUILD

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,40 @@ envoy_cc_test_library(
9191
],
9292
)
9393

94+
envoy_proto_library(
95+
name = "conn_manager_impl_fuzz_proto",
96+
srcs = ["conn_manager_impl_fuzz.proto"],
97+
external_deps = ["well_known_protos"],
98+
generate_python = 0,
99+
deps = [
100+
"//test/fuzz:common_proto",
101+
],
102+
)
103+
104+
envoy_cc_fuzz_test(
105+
name = "conn_manager_impl_fuzz_test",
106+
srcs = ["conn_manager_impl_fuzz_test.cc"],
107+
corpus = "conn_manager_impl_corpus",
108+
deps = [
109+
":conn_manager_impl_fuzz_proto",
110+
"//source/common/common:empty_string",
111+
"//source/common/http:conn_manager_lib",
112+
"//source/common/http:date_provider_lib",
113+
"//source/common/network:address_lib",
114+
"//source/common/network:utility_lib",
115+
"//test/fuzz:utility_lib",
116+
"//test/mocks/access_log:access_log_mocks",
117+
"//test/mocks/http:http_mocks",
118+
"//test/mocks/local_info:local_info_mocks",
119+
"//test/mocks/network:network_mocks",
120+
"//test/mocks/runtime:runtime_mocks",
121+
"//test/mocks/ssl:ssl_mocks",
122+
"//test/mocks/tracing:tracing_mocks",
123+
"//test/mocks/upstream:upstream_mocks",
124+
"@envoy_api//envoy/config/filter/network/http_connection_manager/v2:http_connection_manager_cc",
125+
],
126+
)
127+
94128
envoy_cc_test(
95129
name = "conn_manager_impl_test",
96130
srcs = ["conn_manager_impl_test.cc"],
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
actions {
2+
new_stream {
3+
request_headers {
4+
headers {
5+
key: "foo"
6+
value: "bar"
7+
}
8+
}
9+
}
10+
}
11+
actions {
12+
stream_action {
13+
stream_id: 0
14+
request {
15+
throw_decoder_exception {}
16+
}
17+
}
18+
}

test/common/http/conn_manager_impl_corpus/empty

Whitespace-only changes.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
actions {
2+
new_stream {
3+
request_headers {
4+
headers {
5+
key: ":method"
6+
value: "GET"
7+
}
8+
headers {
9+
key: ":path"
10+
value: "/"
11+
}
12+
headers {
13+
key: ":scheme"
14+
value: "http"
15+
}
16+
headers {
17+
key: ":authority"
18+
value: "foo.com"
19+
}
20+
headers {
21+
key: "blah"
22+
value: "nosniff"
23+
}
24+
headers {
25+
key: "cookie"
26+
value: "foo=bar"
27+
}
28+
headers {
29+
key: "cookie"
30+
value: "foo2=bar2"
31+
}
32+
}
33+
}
34+
}
35+
actions {
36+
stream_action {
37+
stream_id: 0
38+
request {
39+
data {
40+
size: 3000000
41+
decoder_filter_callback_action {
42+
add_decoded_data {
43+
size: 1000000
44+
}
45+
}
46+
status: DATA_STOP_ITERATION_AND_BUFFER
47+
}
48+
}
49+
}
50+
}
51+
actions {
52+
stream_action {
53+
stream_id: 0
54+
request {
55+
continue_decoding {}
56+
}
57+
}
58+
}
59+
actions {
60+
stream_action {
61+
stream_id: 0
62+
response {
63+
continue_100_headers {}
64+
}
65+
}
66+
}
67+
actions {
68+
stream_action {
69+
stream_id: 0
70+
response {
71+
headers {
72+
headers {
73+
key: ":status"
74+
value: "200"
75+
}
76+
}
77+
}
78+
}
79+
}
80+
actions {
81+
stream_action {
82+
stream_id: 0
83+
response {
84+
data: 5
85+
}
86+
}
87+
}
88+
actions {
89+
stream_action {
90+
stream_id: 0
91+
request {
92+
trailers {
93+
headers {
94+
headers {
95+
key: "foo"
96+
value: "bar"
97+
}
98+
}
99+
decoder_filter_callback_action {
100+
add_decoded_data {
101+
size: 1000000
102+
}
103+
}
104+
}
105+
}
106+
}
107+
}
108+
actions {
109+
stream_action {
110+
stream_id: 0
111+
response {
112+
trailers {
113+
headers {
114+
key: "foo"
115+
value: "bar"
116+
}
117+
}
118+
}
119+
}
120+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
actions {
2+
new_stream {
3+
request_headers {
4+
headers {
5+
key: "foo"
6+
value: "bar"
7+
}
8+
}
9+
}
10+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
syntax = "proto3";
2+
3+
package test.common.http;
4+
5+
import "google/protobuf/empty.proto";
6+
7+
import "test/fuzz/common.proto";
8+
9+
// Structured input for conn_manager_impl_fuzz_test.
10+
11+
message NewStream {
12+
test.fuzz.Headers request_headers = 1;
13+
bool end_stream = 2;
14+
// TODO(htuch): Support stop/continue status with headers.
15+
}
16+
17+
enum HeaderStatus {
18+
HEADER_CONTINUE = 0;
19+
HEADER_STOP_ITERATION = 1;
20+
}
21+
22+
enum DataStatus {
23+
DATA_CONTINUE = 0;
24+
DATA_STOP_ITERATION_AND_BUFFER = 1;
25+
DATA_STOP_ITERATION_AND_WATERMARK = 2;
26+
DATA_STOP_ITERATION_NO_BUFFER = 3;
27+
}
28+
29+
enum TrailerStatus {
30+
TRAILER_CONTINUE = 0;
31+
TRAILER_STOP_ITERATION = 1;
32+
}
33+
34+
message DecoderFilterCallbackAction {
35+
message AddDecodedData {
36+
uint32 size = 1;
37+
bool streaming = 2;
38+
}
39+
oneof decoder_filter_callback_action_selector {
40+
// TODO(htuch): More decoder filer callback actions
41+
AddDecodedData add_decoded_data = 1;
42+
}
43+
}
44+
45+
message RequestAction {
46+
message DataAction {
47+
uint32 size = 1;
48+
bool end_stream = 2;
49+
DataStatus status = 3;
50+
DecoderFilterCallbackAction decoder_filter_callback_action = 4;
51+
}
52+
message TrailerAction {
53+
test.fuzz.Headers headers = 1;
54+
TrailerStatus status = 2;
55+
DecoderFilterCallbackAction decoder_filter_callback_action = 3;
56+
}
57+
oneof request_action_selector {
58+
DataAction data = 1;
59+
TrailerAction trailers = 2;
60+
google.protobuf.Empty continue_decoding = 3;
61+
google.protobuf.Empty throw_decoder_exception = 4;
62+
// TODO(htuch): Model and fuzz watermark events.
63+
}
64+
}
65+
66+
// TODO(htuch): Model and fuzz encoder filter buffering/resumption and different status returns.
67+
message ResponseAction {
68+
oneof response_action_selector {
69+
test.fuzz.Headers continue_100_headers = 1;
70+
test.fuzz.Headers headers = 2;
71+
uint32 data = 3;
72+
test.fuzz.Headers trailers = 4;
73+
// TODO(htuch): Model and fuzz watermark events.
74+
}
75+
bool end_stream = 7;
76+
}
77+
78+
message StreamAction {
79+
uint32 stream_id = 1;
80+
oneof stream_action_selector {
81+
RequestAction request = 2;
82+
ResponseAction response = 3;
83+
}
84+
}
85+
86+
message Action {
87+
oneof action_selector {
88+
// Create new stream.
89+
NewStream new_stream = 1;
90+
// Perform an action on an existing stream.
91+
StreamAction stream_action = 2;
92+
}
93+
}
94+
95+
message ConnManagerImplTestCase {
96+
repeated Action actions = 1;
97+
}

0 commit comments

Comments
 (0)