Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/test/integration/h2_fuzz.cc
Line
Count
Source (jump to first uncovered line)
1
#include "test/integration/h2_fuzz.h"
2
3
#include <functional>
4
5
#include "source/common/common/assert.h"
6
#include "source/common/common/base64.h"
7
#include "source/common/common/logger.h"
8
9
#include "test/test_common/environment.h"
10
11
namespace Envoy {
12
13
using namespace Envoy::Http::Http2;
14
15
namespace {
16
17
static Http2Frame::HeadersFlags
18
179
unifyHeadersFlags(const Protobuf::RepeatedField<int>& headers_flags) {
19
179
  int unified_flags = 0;
20
179
  for (const auto& flag : headers_flags) {
21
122
    unified_flags |= flag;
22
122
  }
23
179
  return static_cast<Http2Frame::HeadersFlags>(unified_flags);
24
179
}
25
26
} // namespace
27
28
void H2FuzzIntegrationTest::sendFrame(const test::integration::H2TestFrame& proto_frame,
29
7.07k
                                      std::function<void(const Http2Frame&)> write_func) {
30
7.07k
  Http2Frame h2_frame;
31
7.07k
  switch (proto_frame.frame_type_case()) {
32
341
  case test::integration::H2TestFrame::kPing:
33
341
    ENVOY_LOG_MISC(trace, "Sending ping frame");
34
341
    h2_frame = Http2Frame::makePingFrame(proto_frame.ping().data());
35
341
    break;
36
826
  case test::integration::H2TestFrame::kSettings: {
37
826
    const Http2Frame::SettingsFlags settings_flags =
38
826
        static_cast<Http2Frame::SettingsFlags>(proto_frame.settings().flags());
39
826
    ENVOY_LOG_MISC(trace, "Sending settings frame");
40
826
    h2_frame = Http2Frame::makeEmptySettingsFrame(settings_flags);
41
826
    break;
42
0
  }
43
68
  case test::integration::H2TestFrame::kHeaders: {
44
68
    const Http2Frame::HeadersFlags headers_flags = unifyHeadersFlags(proto_frame.headers().flags());
45
68
    const uint32_t stream_idx = proto_frame.headers().stream_index();
46
68
    ENVOY_LOG_MISC(trace, "Sending headers frame");
47
68
    h2_frame = Http2Frame::makeEmptyHeadersFrame(stream_idx, headers_flags);
48
68
    break;
49
0
  }
50
76
  case test::integration::H2TestFrame::kContinuation: {
51
76
    const Http2Frame::HeadersFlags headers_flags =
52
76
        unifyHeadersFlags(proto_frame.continuation().flags());
53
76
    const uint32_t stream_idx = proto_frame.continuation().stream_index();
54
76
    ENVOY_LOG_MISC(trace, "Sending continuation frame");
55
76
    h2_frame = Http2Frame::makeEmptyContinuationFrame(stream_idx, headers_flags);
56
76
    break;
57
0
  }
58
176
  case test::integration::H2TestFrame::kData: {
59
176
    const Http2Frame::DataFlags data_flags =
60
176
        static_cast<Http2Frame::DataFlags>(proto_frame.data().flags());
61
176
    const uint32_t stream_idx = proto_frame.data().stream_index();
62
176
    ENVOY_LOG_MISC(trace, "Sending data frame");
63
176
    h2_frame = Http2Frame::makeEmptyDataFrame(stream_idx, data_flags);
64
176
    break;
65
0
  }
66
280
  case test::integration::H2TestFrame::kPriority: {
67
280
    const uint32_t stream_idx = proto_frame.priority().stream_index();
68
280
    const uint32_t dependent_idx = proto_frame.priority().dependent_index();
69
280
    ENVOY_LOG_MISC(trace, "Sending priority frame");
70
280
    h2_frame = Http2Frame::makePriorityFrame(stream_idx, dependent_idx);
71
280
    break;
72
0
  }
73
35
  case test::integration::H2TestFrame::kPushPromise: {
74
35
    const Http2Frame::HeadersFlags headers_flags =
75
35
        unifyHeadersFlags(proto_frame.push_promise().flags());
76
35
    const uint32_t stream_idx = proto_frame.push_promise().stream_index();
77
35
    const uint32_t promised_stream_idx = proto_frame.push_promise().promised_stream_index();
78
35
    ENVOY_LOG_MISC(trace, "Sending push promise frame");
79
35
    h2_frame =
80
35
        Http2Frame::makeEmptyPushPromiseFrame(stream_idx, promised_stream_idx, headers_flags);
81
35
    break;
82
0
  }
83
79
  case test::integration::H2TestFrame::kResetStream: {
84
79
    const uint32_t stream_idx = proto_frame.reset_stream().stream_index();
85
79
    const Http2Frame::ErrorCode error_code =
86
79
        static_cast<Http2Frame::ErrorCode>(proto_frame.reset_stream().error_code());
87
79
    ENVOY_LOG_MISC(trace, "Sending reset stream frame");
88
79
    h2_frame = Http2Frame::makeResetStreamFrame(stream_idx, error_code);
89
79
    break;
90
0
  }
91
103
  case test::integration::H2TestFrame::kGoAway: {
92
103
    const uint32_t last_stream_idx = proto_frame.go_away().last_stream_index();
93
103
    const Http2Frame::ErrorCode error_code =
94
103
        static_cast<Http2Frame::ErrorCode>(proto_frame.go_away().error_code());
95
103
    ENVOY_LOG_MISC(trace, "Sending go-away frame");
96
103
    h2_frame = Http2Frame::makeEmptyGoAwayFrame(last_stream_idx, error_code);
97
103
    break;
98
0
  }
99
135
  case test::integration::H2TestFrame::kWindowUpdate: {
100
135
    const uint32_t stream_idx = proto_frame.window_update().stream_index();
101
135
    const uint32_t increment = proto_frame.window_update().increment();
102
135
    ENVOY_LOG_MISC(trace, "Sending windows_update frame");
103
135
    h2_frame = Http2Frame::makeWindowUpdateFrame(stream_idx, increment);
104
135
    break;
105
0
  }
106
45
  case test::integration::H2TestFrame::kMalformedRequest: {
107
45
    const uint32_t stream_idx = proto_frame.malformed_request().stream_index();
108
45
    ENVOY_LOG_MISC(trace, "Sending malformed_request frame");
109
45
    h2_frame = Http2Frame::makeMalformedRequest(stream_idx);
110
45
    break;
111
0
  }
112
34
  case test::integration::H2TestFrame::kMalformedRequestWithZerolenHeader: {
113
34
    const uint32_t stream_idx = proto_frame.malformed_request_with_zerolen_header().stream_index();
114
34
    const absl::string_view host = proto_frame.malformed_request_with_zerolen_header().host();
115
34
    const absl::string_view path = proto_frame.malformed_request_with_zerolen_header().path();
116
34
    ENVOY_LOG_MISC(trace, "Sending malformed_request_with_zerolen_header");
117
34
    h2_frame = Http2Frame::makeMalformedRequestWithZerolenHeader(stream_idx, host, path);
118
34
    break;
119
0
  }
120
244
  case test::integration::H2TestFrame::kRequest: {
121
244
    const uint32_t stream_idx = proto_frame.request().stream_index();
122
244
    const absl::string_view host = proto_frame.request().host();
123
244
    const absl::string_view path = proto_frame.request().path();
124
244
    ENVOY_LOG_MISC(trace, "Sending request");
125
244
    h2_frame = Http2Frame::makeRequest(stream_idx, host, path);
126
244
    break;
127
0
  }
128
170
  case test::integration::H2TestFrame::kPostRequest: {
129
170
    const uint32_t stream_idx = proto_frame.post_request().stream_index();
130
170
    const absl::string_view host = proto_frame.post_request().host();
131
170
    const absl::string_view path = proto_frame.post_request().path();
132
170
    ENVOY_LOG_MISC(trace, "Sending post request");
133
170
    h2_frame = Http2Frame::makePostRequest(stream_idx, host, path);
134
170
    break;
135
0
  }
136
2.25k
  case test::integration::H2TestFrame::kMetadata: {
137
2.25k
    const Http2Frame::MetadataFlags metadata_flags =
138
2.25k
        static_cast<Http2Frame::MetadataFlags>(proto_frame.metadata().flags());
139
2.25k
    const uint32_t stream_idx = proto_frame.metadata().stream_index();
140
2.25k
    Http::MetadataMap metadata_map;
141
8.06k
    for (const auto& metadataPair : proto_frame.metadata().metadata().metadata()) {
142
8.06k
      metadata_map.insert(metadataPair);
143
8.06k
    }
144
2.25k
    ENVOY_LOG_MISC(trace, "Sending metadata frame.");
145
2.25k
    h2_frame =
146
2.25k
        Http2Frame::makeMetadataFrameFromMetadataMap(stream_idx, metadata_map, metadata_flags);
147
2.25k
    break;
148
0
  }
149
58
  case test::integration::H2TestFrame::kStatus: {
150
58
    const std::string status = proto_frame.status().status();
151
58
    const uint32_t stream_idx = proto_frame.status().stream_index();
152
58
    ENVOY_LOG_MISC(trace, "Sending status frame");
153
58
    h2_frame = Http2Frame::makeHeadersFrameWithStatus(status, stream_idx);
154
58
    break;
155
0
  }
156
391
  case test::integration::H2TestFrame::kGeneric: {
157
391
    const absl::string_view frame_bytes = proto_frame.generic().frame_bytes();
158
391
    ENVOY_LOG_MISC(trace, "Sending generic frame");
159
391
    h2_frame = Http2Frame::makeGenericFrame(frame_bytes);
160
391
    break;
161
0
  }
162
1.75k
  default:
163
1.75k
    ENVOY_LOG_MISC(debug, "Proto-frame not supported!");
164
1.75k
    break;
165
7.07k
  }
166
167
7.07k
  write_func(h2_frame);
168
7.07k
}
169
170
void H2FuzzIntegrationTest::replay(const test::integration::H2CaptureFuzzTestCase& input,
171
1.04k
                                   bool ignore_response) {
172
1.04k
  struct Init {
173
1.04k
    Init(H2FuzzIntegrationTest* test) { test->initialize(); }
174
1.04k
  };
175
1.04k
  PERSISTENT_FUZZ_VAR(Init, initialized, (this));
176
1.04k
  UNREFERENCED_PARAMETER(initialized);
177
1.04k
  IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("http"));
178
1.04k
  FakeRawConnectionPtr fake_upstream_connection;
179
1.04k
  bool stop_further_inputs = false;
180
1.04k
  bool preamble_sent = false;
181
10.5k
  for (int i = 0; i < input.events().size(); ++i) {
182
9.57k
    if (stop_further_inputs) {
183
109
      break;
184
109
    }
185
9.46k
    const auto& event = input.events(i);
186
9.46k
    ENVOY_LOG_MISC(debug, "Processing event: {}", event.DebugString());
187
    // If we're disconnected, we fail out.
188
9.46k
    if (!tcp_client->connected()) {
189
2
      ENVOY_LOG_MISC(debug, "Disconnected, no further event processing.");
190
2
      break;
191
2
    }
192
9.46k
    switch (event.event_selector_case()) {
193
786
    case test::integration::Event::kDownstreamSendEvent: {
194
3.54k
      auto downstream_write_func = [&](const Http2Frame& h2_frame) -> void {
195
3.54k
        ASSERT_TRUE(tcp_client->write(std::string(h2_frame), false, false));
196
3.54k
      };
197
786
      if (!preamble_sent) {
198
        // Start H2 session - send hello string
199
315
        ASSERT_TRUE(tcp_client->write(Http2Frame::Preamble, false, false));
200
315
        preamble_sent = true;
201
315
      }
202
3.55k
      for (auto& frame : event.downstream_send_event().h2_frames()) {
203
3.55k
        if (!tcp_client->connected()) {
204
4
          ENVOY_LOG_MISC(debug,
205
4
                         "Disconnected, avoiding sending data, no further event processing.");
206
4
          break;
207
4
        }
208
209
3.54k
        ENVOY_LOG_MISC(trace, "sending downstream frame");
210
3.54k
        sendFrame(frame, downstream_write_func);
211
3.54k
      }
212
786
      break;
213
786
    }
214
797
    case test::integration::Event::kUpstreamSendEvent: {
215
797
      if (ignore_response) {
216
346
        break;
217
346
      }
218
451
      if (fake_upstream_connection == nullptr) {
219
197
        if (!fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection, max_wait_ms_)) {
220
          // If we timed out, we fail out.
221
139
          if (tcp_client->connected()) {
222
139
            tcp_client->close();
223
139
          }
224
139
          stop_further_inputs = true;
225
139
          break;
226
139
        }
227
197
      }
228
      // If we're no longer connected, we're done.
229
312
      if (!fake_upstream_connection->connected()) {
230
6
        if (tcp_client->connected()) {
231
6
          tcp_client->close();
232
6
        }
233
6
        stop_further_inputs = true;
234
6
        break;
235
6
      }
236
306
      {
237
3.52k
        auto upstream_write_func = [&](const Http2Frame& h2_frame) -> void {
238
3.52k
          AssertionResult result = fake_upstream_connection->write(std::string(h2_frame));
239
3.52k
          RELEASE_ASSERT(result, result.message());
240
3.52k
        };
241
3.54k
        for (auto& frame : event.upstream_send_event().h2_frames()) {
242
3.54k
          if (!fake_upstream_connection->connected()) {
243
25
            ENVOY_LOG_MISC(
244
25
                debug,
245
25
                "Upstream disconnected, avoiding sending data, no further event processing.");
246
25
            stop_further_inputs = true;
247
25
            break;
248
25
          }
249
250
3.52k
          ENVOY_LOG_MISC(trace, "sending upstream frame");
251
3.52k
          sendFrame(frame, upstream_write_func);
252
3.52k
        }
253
306
      }
254
306
      break;
255
312
    }
256
7.87k
    default:
257
      // Maybe nothing is set?
258
7.87k
      break;
259
9.46k
    }
260
9.46k
  }
261
1.04k
  if (fake_upstream_connection != nullptr) {
262
58
    if (fake_upstream_connection->connected()) {
263
20
      AssertionResult result = fake_upstream_connection->close();
264
20
      RELEASE_ASSERT(result, result.message());
265
20
    }
266
58
    AssertionResult result = fake_upstream_connection->waitForDisconnect();
267
58
    RELEASE_ASSERT(result, result.message());
268
58
  }
269
1.04k
  if (tcp_client->connected()) {
270
1.03k
    tcp_client->close();
271
1.03k
  }
272
1.04k
}
273
274
} // namespace Envoy