1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fuzzer/FuzzedDataProvider.h>
6
7 #include <algorithm>
8 #include <cstddef>
9 #include <cstdint>
10 #include <string>
11 #include <utility>
12
13 #include "absl/strings/string_view.h"
14 #include "quiche/quic/core/http/quic_header_list.h"
15 #include "quiche/quic/core/qpack/qpack_decoded_headers_accumulator.h"
16 #include "quiche/quic/core/qpack/qpack_decoder.h"
17 #include "quiche/quic/core/qpack/qpack_encoder.h"
18 #include "quiche/quic/core/qpack/qpack_stream_sender_delegate.h"
19 #include "quiche/quic/core/qpack/value_splitting_header_list.h"
20 #include "quiche/quic/core/quic_error_codes.h"
21 #include "quiche/quic/test_tools/qpack/qpack_decoder_test_utils.h"
22 #include "quiche/quic/test_tools/qpack/qpack_encoder_peer.h"
23 #include "quiche/common/quiche_circular_deque.h"
24 #include "quiche/spdy/core/http2_header_block.h"
25
26 namespace quic {
27 namespace test {
28 namespace {
29
30 // Find the first occurrence of invalid characters NUL, LF, CR in |*value| and
31 // remove that and the remaining of the string.
TruncateValueOnInvalidChars(std::string * value)32 void TruncateValueOnInvalidChars(std::string* value) {
33 for (auto it = value->begin(); it != value->end(); ++it) {
34 if (*it == '\0' || *it == '\n' || *it == '\r') {
35 value->erase(it, value->end());
36 return;
37 }
38 }
39 }
40
41 } // anonymous namespace
42
43 // Class to hold QpackEncoder and its DecoderStreamErrorDelegate.
44 class EncodingEndpoint {
45 public:
EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,uint64_t maximum_blocked_streams,HuffmanEncoding huffman_encoding)46 EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,
47 uint64_t maximum_blocked_streams,
48 HuffmanEncoding huffman_encoding)
49 : encoder_(&decoder_stream_error_delegate, huffman_encoding) {
50 encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
51 encoder_.SetMaximumBlockedStreams(maximum_blocked_streams);
52 }
53
~EncodingEndpoint()54 ~EncodingEndpoint() {
55 // Every reference should be acknowledged.
56 QUICHE_CHECK_EQ(std::numeric_limits<uint64_t>::max(),
57 QpackEncoderPeer::smallest_blocking_index(&encoder_));
58 }
59
set_qpack_stream_sender_delegate(QpackStreamSenderDelegate * delegate)60 void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
61 encoder_.set_qpack_stream_sender_delegate(delegate);
62 }
63
SetDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity)64 void SetDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity) {
65 encoder_.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
66 }
67
decoder_stream_receiver()68 QpackStreamReceiver* decoder_stream_receiver() {
69 return encoder_.decoder_stream_receiver();
70 }
71
EncodeHeaderList(QuicStreamId stream_id,const spdy::Http2HeaderBlock & header_list)72 std::string EncodeHeaderList(QuicStreamId stream_id,
73 const spdy::Http2HeaderBlock& header_list) {
74 return encoder_.EncodeHeaderList(stream_id, header_list, nullptr);
75 }
76
77 private:
78 // DecoderStreamErrorDelegate implementation that crashes on error.
79 class CrashingDecoderStreamErrorDelegate
80 : public QpackEncoder::DecoderStreamErrorDelegate {
81 public:
82 ~CrashingDecoderStreamErrorDelegate() override = default;
83
OnDecoderStreamError(QuicErrorCode error_code,absl::string_view error_message)84 void OnDecoderStreamError(QuicErrorCode error_code,
85 absl::string_view error_message) override {
86 QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
87 << error_message;
88 }
89 };
90
91 CrashingDecoderStreamErrorDelegate decoder_stream_error_delegate;
92 QpackEncoder encoder_;
93 };
94
95 // Class that receives all header blocks from the encoding endpoint and passes
96 // them to the decoding endpoint, with delay determined by fuzzer data,
97 // preserving order within each stream but not among streams.
98 class DelayedHeaderBlockTransmitter {
99 public:
100 class Visitor {
101 public:
102 virtual ~Visitor() = default;
103
104 // If decoding of the previous header block is still in progress, then
105 // DelayedHeaderBlockTransmitter will not start transmitting the next header
106 // block.
107 virtual bool IsDecodingInProgressOnStream(QuicStreamId stream_id) = 0;
108
109 // Called when a header block starts.
110 virtual void OnHeaderBlockStart(QuicStreamId stream_id) = 0;
111 // Called when part or all of a header block is transmitted.
112 virtual void OnHeaderBlockFragment(QuicStreamId stream_id,
113 absl::string_view data) = 0;
114 // Called when transmission of a header block is complete.
115 virtual void OnHeaderBlockEnd(QuicStreamId stream_id) = 0;
116 };
117
DelayedHeaderBlockTransmitter(Visitor * visitor,FuzzedDataProvider * provider)118 DelayedHeaderBlockTransmitter(Visitor* visitor, FuzzedDataProvider* provider)
119 : visitor_(visitor), provider_(provider) {}
120
~DelayedHeaderBlockTransmitter()121 ~DelayedHeaderBlockTransmitter() { QUICHE_CHECK(header_blocks_.empty()); }
122
123 // Enqueues |encoded_header_block| for delayed transmission.
SendEncodedHeaderBlock(QuicStreamId stream_id,std::string encoded_header_block)124 void SendEncodedHeaderBlock(QuicStreamId stream_id,
125 std::string encoded_header_block) {
126 auto it = header_blocks_.lower_bound(stream_id);
127 if (it == header_blocks_.end() || it->first != stream_id) {
128 it = header_blocks_.insert(it, {stream_id, {}});
129 }
130 QUICHE_CHECK_EQ(stream_id, it->first);
131 it->second.push(HeaderBlock(std::move(encoded_header_block)));
132 }
133
134 // Release some (possibly none) header block data.
MaybeTransmitSomeData()135 void MaybeTransmitSomeData() {
136 if (header_blocks_.empty()) {
137 return;
138 }
139
140 auto index =
141 provider_->ConsumeIntegralInRange<size_t>(0, header_blocks_.size() - 1);
142 auto it = header_blocks_.begin();
143 std::advance(it, index);
144 const QuicStreamId stream_id = it->first;
145
146 // Do not start new header block if processing of previous header block is
147 // blocked.
148 if (visitor_->IsDecodingInProgressOnStream(stream_id)) {
149 return;
150 }
151
152 auto& header_block_queue = it->second;
153 HeaderBlock& header_block = header_block_queue.front();
154
155 if (header_block.ConsumedLength() == 0) {
156 visitor_->OnHeaderBlockStart(stream_id);
157 }
158
159 QUICHE_DCHECK_NE(0u, header_block.RemainingLength());
160
161 size_t length = provider_->ConsumeIntegralInRange<size_t>(
162 1, header_block.RemainingLength());
163 visitor_->OnHeaderBlockFragment(stream_id, header_block.Consume(length));
164
165 QUICHE_DCHECK_NE(0u, header_block.ConsumedLength());
166
167 if (header_block.RemainingLength() == 0) {
168 visitor_->OnHeaderBlockEnd(stream_id);
169
170 header_block_queue.pop();
171 if (header_block_queue.empty()) {
172 header_blocks_.erase(it);
173 }
174 }
175 }
176
177 // Release all header block data. Must be called before destruction. All
178 // encoder stream data must have been released before calling Flush() so that
179 // all header blocks can be decoded synchronously.
Flush()180 void Flush() {
181 while (!header_blocks_.empty()) {
182 auto it = header_blocks_.begin();
183 const QuicStreamId stream_id = it->first;
184
185 auto& header_block_queue = it->second;
186 HeaderBlock& header_block = header_block_queue.front();
187
188 if (header_block.ConsumedLength() == 0) {
189 QUICHE_CHECK(!visitor_->IsDecodingInProgressOnStream(stream_id));
190 visitor_->OnHeaderBlockStart(stream_id);
191 }
192
193 QUICHE_DCHECK_NE(0u, header_block.RemainingLength());
194
195 visitor_->OnHeaderBlockFragment(stream_id,
196 header_block.ConsumeRemaining());
197
198 QUICHE_DCHECK_NE(0u, header_block.ConsumedLength());
199 QUICHE_DCHECK_EQ(0u, header_block.RemainingLength());
200
201 visitor_->OnHeaderBlockEnd(stream_id);
202 QUICHE_CHECK(!visitor_->IsDecodingInProgressOnStream(stream_id));
203
204 header_block_queue.pop();
205 if (header_block_queue.empty()) {
206 header_blocks_.erase(it);
207 }
208 }
209 }
210
211 private:
212 // Helper class that allows the header block to be consumed in parts.
213 class HeaderBlock {
214 public:
HeaderBlock(std::string data)215 explicit HeaderBlock(std::string data)
216 : data_(std::move(data)), offset_(0) {
217 // Valid QPACK header block cannot be empty.
218 QUICHE_DCHECK(!data_.empty());
219 }
220
ConsumedLength() const221 size_t ConsumedLength() const { return offset_; }
222
RemainingLength() const223 size_t RemainingLength() const { return data_.length() - offset_; }
224
Consume(size_t length)225 absl::string_view Consume(size_t length) {
226 QUICHE_DCHECK_NE(0u, length);
227 QUICHE_DCHECK_LE(length, RemainingLength());
228
229 absl::string_view consumed = absl::string_view(&data_[offset_], length);
230 offset_ += length;
231 return consumed;
232 }
233
ConsumeRemaining()234 absl::string_view ConsumeRemaining() { return Consume(RemainingLength()); }
235
236 private:
237 // Complete header block.
238 const std::string data_;
239
240 // Offset of the part not consumed yet. Same as number of consumed bytes.
241 size_t offset_;
242 };
243
244 Visitor* const visitor_;
245 FuzzedDataProvider* const provider_;
246
247 std::map<QuicStreamId, std::queue<HeaderBlock>> header_blocks_;
248 };
249
250 // Class to decode and verify a header block, and in case of blocked decoding,
251 // keep necessary decoding context while waiting for decoding to complete.
252 class VerifyingDecoder : public QpackDecodedHeadersAccumulator::Visitor {
253 public:
254 class Visitor {
255 public:
256 virtual ~Visitor() = default;
257
258 // Called when header block is decoded, either synchronously or
259 // asynchronously. Might destroy VerifyingDecoder.
260 virtual void OnHeaderBlockDecoded(QuicStreamId stream_id) = 0;
261 };
262
VerifyingDecoder(QuicStreamId stream_id,Visitor * visitor,QpackDecoder * qpack_decoder,QuicHeaderList expected_header_list)263 VerifyingDecoder(QuicStreamId stream_id, Visitor* visitor,
264 QpackDecoder* qpack_decoder,
265 QuicHeaderList expected_header_list)
266 : stream_id_(stream_id),
267 visitor_(visitor),
268 accumulator_(
269 stream_id, qpack_decoder, this,
270 /* max_header_list_size = */ std::numeric_limits<size_t>::max()),
271 expected_header_list_(std::move(expected_header_list)) {}
272
273 VerifyingDecoder(const VerifyingDecoder&) = delete;
274 VerifyingDecoder& operator=(const VerifyingDecoder&) = delete;
275 // VerifyingDecoder must not be moved because it passes |this| to
276 // |accumulator_| upon construction.
277 VerifyingDecoder(VerifyingDecoder&&) = delete;
278 VerifyingDecoder& operator=(VerifyingDecoder&&) = delete;
279
280 virtual ~VerifyingDecoder() = default;
281
282 // QpackDecodedHeadersAccumulator::Visitor implementation.
OnHeadersDecoded(QuicHeaderList headers,bool header_list_size_limit_exceeded)283 void OnHeadersDecoded(QuicHeaderList headers,
284 bool header_list_size_limit_exceeded) override {
285 // Verify headers.
286 QUICHE_CHECK(!header_list_size_limit_exceeded);
287 QUICHE_CHECK(expected_header_list_ == headers);
288
289 // Might destroy |this|.
290 visitor_->OnHeaderBlockDecoded(stream_id_);
291 }
292
OnHeaderDecodingError(QuicErrorCode error_code,absl::string_view error_message)293 void OnHeaderDecodingError(QuicErrorCode error_code,
294 absl::string_view error_message) override {
295 QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
296 << error_message;
297 }
298
Decode(absl::string_view data)299 void Decode(absl::string_view data) { accumulator_.Decode(data); }
300
EndHeaderBlock()301 void EndHeaderBlock() { accumulator_.EndHeaderBlock(); }
302
303 private:
304 QuicStreamId stream_id_;
305 Visitor* const visitor_;
306 QpackDecodedHeadersAccumulator accumulator_;
307 QuicHeaderList expected_header_list_;
308 };
309
310 // Class that holds QpackDecoder and its EncoderStreamErrorDelegate, and creates
311 // and keeps VerifyingDecoders for each received header block until decoding is
312 // complete.
313 class DecodingEndpoint : public DelayedHeaderBlockTransmitter::Visitor,
314 public VerifyingDecoder::Visitor {
315 public:
DecodingEndpoint(uint64_t maximum_dynamic_table_capacity,uint64_t maximum_blocked_streams,FuzzedDataProvider * provider)316 DecodingEndpoint(uint64_t maximum_dynamic_table_capacity,
317 uint64_t maximum_blocked_streams,
318 FuzzedDataProvider* provider)
319 : decoder_(maximum_dynamic_table_capacity, maximum_blocked_streams,
320 &encoder_stream_error_delegate_),
321 provider_(provider) {}
322
~DecodingEndpoint()323 ~DecodingEndpoint() override {
324 // All decoding must have been completed.
325 QUICHE_CHECK(expected_header_lists_.empty());
326 QUICHE_CHECK(verifying_decoders_.empty());
327 }
328
set_qpack_stream_sender_delegate(QpackStreamSenderDelegate * delegate)329 void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
330 decoder_.set_qpack_stream_sender_delegate(delegate);
331 }
332
encoder_stream_receiver()333 QpackStreamReceiver* encoder_stream_receiver() {
334 return decoder_.encoder_stream_receiver();
335 }
336
AddExpectedHeaderList(QuicStreamId stream_id,QuicHeaderList expected_header_list)337 void AddExpectedHeaderList(QuicStreamId stream_id,
338 QuicHeaderList expected_header_list) {
339 auto it = expected_header_lists_.lower_bound(stream_id);
340 if (it == expected_header_lists_.end() || it->first != stream_id) {
341 it = expected_header_lists_.insert(it, {stream_id, {}});
342 }
343 QUICHE_CHECK_EQ(stream_id, it->first);
344 it->second.push(std::move(expected_header_list));
345 }
346
347 // VerifyingDecoder::Visitor implementation.
OnHeaderBlockDecoded(QuicStreamId stream_id)348 void OnHeaderBlockDecoded(QuicStreamId stream_id) override {
349 auto result = verifying_decoders_.erase(stream_id);
350 QUICHE_CHECK_EQ(1u, result);
351 }
352
353 // DelayedHeaderBlockTransmitter::Visitor implementation.
IsDecodingInProgressOnStream(QuicStreamId stream_id)354 bool IsDecodingInProgressOnStream(QuicStreamId stream_id) override {
355 return verifying_decoders_.find(stream_id) != verifying_decoders_.end();
356 }
357
OnHeaderBlockStart(QuicStreamId stream_id)358 void OnHeaderBlockStart(QuicStreamId stream_id) override {
359 QUICHE_CHECK(!IsDecodingInProgressOnStream(stream_id));
360 auto it = expected_header_lists_.find(stream_id);
361 QUICHE_CHECK(it != expected_header_lists_.end());
362
363 auto& header_list_queue = it->second;
364 QuicHeaderList expected_header_list = std::move(header_list_queue.front());
365
366 header_list_queue.pop();
367 if (header_list_queue.empty()) {
368 expected_header_lists_.erase(it);
369 }
370
371 auto verifying_decoder = std::make_unique<VerifyingDecoder>(
372 stream_id, this, &decoder_, std::move(expected_header_list));
373 auto result =
374 verifying_decoders_.insert({stream_id, std::move(verifying_decoder)});
375 QUICHE_CHECK(result.second);
376 }
377
OnHeaderBlockFragment(QuicStreamId stream_id,absl::string_view data)378 void OnHeaderBlockFragment(QuicStreamId stream_id,
379 absl::string_view data) override {
380 auto it = verifying_decoders_.find(stream_id);
381 QUICHE_CHECK(it != verifying_decoders_.end());
382 it->second->Decode(data);
383 }
384
OnHeaderBlockEnd(QuicStreamId stream_id)385 void OnHeaderBlockEnd(QuicStreamId stream_id) override {
386 auto it = verifying_decoders_.find(stream_id);
387 QUICHE_CHECK(it != verifying_decoders_.end());
388 it->second->EndHeaderBlock();
389 }
390
391 // Flush decoder stream data buffered within the decoder.
FlushDecoderStream()392 void FlushDecoderStream() { decoder_.FlushDecoderStream(); }
MaybeFlushDecoderStream()393 void MaybeFlushDecoderStream() {
394 if (provider_->ConsumeBool()) {
395 FlushDecoderStream();
396 }
397 }
398
399 private:
400 // EncoderStreamErrorDelegate implementation that crashes on error.
401 class CrashingEncoderStreamErrorDelegate
402 : public QpackDecoder::EncoderStreamErrorDelegate {
403 public:
404 ~CrashingEncoderStreamErrorDelegate() override = default;
405
OnEncoderStreamError(QuicErrorCode error_code,absl::string_view error_message)406 void OnEncoderStreamError(QuicErrorCode error_code,
407 absl::string_view error_message) override {
408 QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
409 << error_message;
410 }
411 };
412
413 CrashingEncoderStreamErrorDelegate encoder_stream_error_delegate_;
414 QpackDecoder decoder_;
415 FuzzedDataProvider* const provider_;
416
417 // Expected header lists in order for each stream.
418 std::map<QuicStreamId, std::queue<QuicHeaderList>> expected_header_lists_;
419
420 // A VerifyingDecoder object keeps context necessary for asynchronously
421 // decoding blocked header blocks. It is destroyed as soon as it signals that
422 // decoding is completed, which might happen synchronously within an
423 // EndHeaderBlock() call.
424 std::map<QuicStreamId, std::unique_ptr<VerifyingDecoder>> verifying_decoders_;
425 };
426
427 // Class that receives encoder stream data from the encoder and passes it to the
428 // decoder, or receives decoder stream data from the decoder and passes it to
429 // the encoder, with delay determined by fuzzer data.
430 class DelayedStreamDataTransmitter : public QpackStreamSenderDelegate {
431 public:
DelayedStreamDataTransmitter(QpackStreamReceiver * receiver,FuzzedDataProvider * provider)432 DelayedStreamDataTransmitter(QpackStreamReceiver* receiver,
433 FuzzedDataProvider* provider)
434 : receiver_(receiver), provider_(provider) {}
435
~DelayedStreamDataTransmitter()436 ~DelayedStreamDataTransmitter() { QUICHE_CHECK(stream_data.empty()); }
437
438 // QpackStreamSenderDelegate implementation.
WriteStreamData(absl::string_view data)439 void WriteStreamData(absl::string_view data) override {
440 stream_data.push_back(std::string(data.data(), data.size()));
441 }
NumBytesBuffered() const442 uint64_t NumBytesBuffered() const override { return 0; }
443
444 // Release some (possibly none) delayed stream data.
MaybeTransmitSomeData()445 void MaybeTransmitSomeData() {
446 auto count = provider_->ConsumeIntegral<uint8_t>();
447 while (!stream_data.empty() && count > 0) {
448 receiver_->Decode(stream_data.front());
449 stream_data.pop_front();
450 --count;
451 }
452 }
453
454 // Release all delayed stream data. Must be called before destruction.
Flush()455 void Flush() {
456 while (!stream_data.empty()) {
457 receiver_->Decode(stream_data.front());
458 stream_data.pop_front();
459 }
460 }
461
462 private:
463 QpackStreamReceiver* const receiver_;
464 FuzzedDataProvider* const provider_;
465 quiche::QuicheCircularDeque<std::string> stream_data;
466 };
467
468 // Generate header list using fuzzer data.
GenerateHeaderList(FuzzedDataProvider * provider)469 spdy::Http2HeaderBlock GenerateHeaderList(FuzzedDataProvider* provider) {
470 spdy::Http2HeaderBlock header_list;
471 uint8_t header_count = provider->ConsumeIntegral<uint8_t>();
472 for (uint8_t header_index = 0; header_index < header_count; ++header_index) {
473 if (provider->remaining_bytes() == 0) {
474 // Do not add more headers if there is no more fuzzer data.
475 break;
476 }
477
478 std::string name;
479 std::string value;
480 switch (provider->ConsumeIntegral<uint8_t>()) {
481 case 0:
482 // Static table entry with no header value.
483 name = ":authority";
484 break;
485 case 1:
486 // Static table entry with no header value, using non-empty header
487 // value.
488 name = ":authority";
489 value = "www.example.org";
490 break;
491 case 2:
492 // Static table entry with header value, using that header value.
493 name = ":accept-encoding";
494 value = "gzip, deflate";
495 break;
496 case 3:
497 // Static table entry with header value, using empty header value.
498 name = ":accept-encoding";
499 break;
500 case 4:
501 // Static table entry with header value, using different, non-empty
502 // header value.
503 name = ":accept-encoding";
504 value = "brotli";
505 break;
506 case 5:
507 // Header name that has multiple entries in the static table,
508 // using header value from one of them.
509 name = ":method";
510 value = "GET";
511 break;
512 case 6:
513 // Header name that has multiple entries in the static table,
514 // using empty header value.
515 name = ":method";
516 break;
517 case 7:
518 // Header name that has multiple entries in the static table,
519 // using different, non-empty header value.
520 name = ":method";
521 value = "CONNECT";
522 break;
523 case 8:
524 // Header name not in the static table, empty header value.
525 name = "foo";
526 value = "";
527 break;
528 case 9:
529 // Header name not in the static table, non-empty fixed header value.
530 name = "foo";
531 value = "bar";
532 break;
533 case 10:
534 // Header name not in the static table, fuzzed header value.
535 name = "foo";
536 value = provider->ConsumeRandomLengthString(128);
537 TruncateValueOnInvalidChars(&value);
538 break;
539 case 11:
540 // Another header name not in the static table, empty header value.
541 name = "bar";
542 value = "";
543 break;
544 case 12:
545 // Another header name not in the static table, non-empty fixed header
546 // value.
547 name = "bar";
548 value = "baz";
549 break;
550 case 13:
551 // Another header name not in the static table, fuzzed header value.
552 name = "bar";
553 value = provider->ConsumeRandomLengthString(128);
554 TruncateValueOnInvalidChars(&value);
555 break;
556 default:
557 // Fuzzed header name and header value.
558 name = provider->ConsumeRandomLengthString(128);
559 value = provider->ConsumeRandomLengthString(128);
560 TruncateValueOnInvalidChars(&value);
561 }
562
563 header_list.AppendValueOrAddHeader(name, value);
564 }
565
566 return header_list;
567 }
568
569 // Splits |*header_list| header values along '\0' or ';' separators.
SplitHeaderList(const spdy::Http2HeaderBlock & header_list)570 QuicHeaderList SplitHeaderList(const spdy::Http2HeaderBlock& header_list) {
571 QuicHeaderList split_header_list;
572 split_header_list.OnHeaderBlockStart();
573
574 size_t total_size = 0;
575 ValueSplittingHeaderList splitting_header_list(&header_list);
576 for (const auto& header : splitting_header_list) {
577 split_header_list.OnHeader(header.first, header.second);
578 total_size += header.first.size() + header.second.size();
579 }
580
581 split_header_list.OnHeaderBlockEnd(total_size, total_size);
582
583 return split_header_list;
584 }
585
586 // This fuzzer exercises QpackEncoder and QpackDecoder. It should be able to
587 // cover all possible code paths of QpackEncoder. However, since the resulting
588 // header block is always valid and is encoded in a particular way, this fuzzer
589 // is not expected to cover all code paths of QpackDecoder. On the other hand,
590 // encoding then decoding is expected to result in the original header list, and
591 // this fuzzer checks for that.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)592 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
593 FuzzedDataProvider provider(data, size);
594
595 // Maximum 256 byte dynamic table. Such a small size helps test draining
596 // entries and eviction.
597 const uint64_t maximum_dynamic_table_capacity =
598 provider.ConsumeIntegral<uint8_t>();
599 // Maximum 256 blocked streams.
600 const uint64_t maximum_blocked_streams = provider.ConsumeIntegral<uint8_t>();
601
602 // Set up encoder.
603 EncodingEndpoint encoder(maximum_dynamic_table_capacity,
604 maximum_blocked_streams,
605 provider.ConsumeBool() ? HuffmanEncoding::kEnabled
606 : HuffmanEncoding::kDisabled);
607
608 // Set up decoder.
609 DecodingEndpoint decoder(maximum_dynamic_table_capacity,
610 maximum_blocked_streams, &provider);
611
612 // Transmit encoder stream data from encoder to decoder.
613 DelayedStreamDataTransmitter encoder_stream_transmitter(
614 decoder.encoder_stream_receiver(), &provider);
615 encoder.set_qpack_stream_sender_delegate(&encoder_stream_transmitter);
616
617 // Use a dynamic table as large as the peer allows. This sends data on the
618 // encoder stream, so it can only be done after delegate is set.
619 encoder.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
620
621 // Transmit decoder stream data from encoder to decoder.
622 DelayedStreamDataTransmitter decoder_stream_transmitter(
623 encoder.decoder_stream_receiver(), &provider);
624 decoder.set_qpack_stream_sender_delegate(&decoder_stream_transmitter);
625
626 // Transmit header blocks from encoder to decoder.
627 DelayedHeaderBlockTransmitter header_block_transmitter(&decoder, &provider);
628
629 // Maximum 256 header lists to limit runtime and memory usage.
630 auto header_list_count = provider.ConsumeIntegral<uint8_t>();
631 while (header_list_count > 0 && provider.remaining_bytes() > 0) {
632 const QuicStreamId stream_id = provider.ConsumeIntegral<uint8_t>();
633
634 // Generate header list.
635 spdy::Http2HeaderBlock header_list = GenerateHeaderList(&provider);
636
637 // Encode header list.
638 std::string encoded_header_block =
639 encoder.EncodeHeaderList(stream_id, header_list);
640
641 // TODO(bnc): Randomly cancel the stream.
642
643 // Encoder splits |header_list| header values along '\0' or ';' separators.
644 // Do the same here so that we get matching results.
645 QuicHeaderList expected_header_list = SplitHeaderList(header_list);
646 decoder.AddExpectedHeaderList(stream_id, std::move(expected_header_list));
647
648 header_block_transmitter.SendEncodedHeaderBlock(
649 stream_id, std::move(encoded_header_block));
650
651 // Transmit some encoder stream data, decoder stream data, or header blocks
652 // on the request stream, repeating a few times.
653 for (auto transmit_data_count = provider.ConsumeIntegralInRange(1, 5);
654 transmit_data_count > 0; --transmit_data_count) {
655 encoder_stream_transmitter.MaybeTransmitSomeData();
656 decoder.MaybeFlushDecoderStream();
657 decoder_stream_transmitter.MaybeTransmitSomeData();
658 header_block_transmitter.MaybeTransmitSomeData();
659 }
660
661 --header_list_count;
662 }
663
664 // Release all delayed encoder stream data so that remaining header blocks can
665 // be decoded synchronously.
666 encoder_stream_transmitter.Flush();
667 // Release all delayed header blocks.
668 header_block_transmitter.Flush();
669 // Flush decoder stream data buffered within the decoder. This will then be
670 // buffered in and delayed by `decoder_stream_transmitter`.
671 decoder.FlushDecoderStream();
672 // Release all delayed decoder stream data.
673 decoder_stream_transmitter.Flush();
674
675 return 0;
676 }
677
678 } // namespace test
679 } // namespace quic
680