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 <cstddef>
8 #include <cstdint>
9 #include <limits>
10 #include <utility>
11
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/qpack/qpack_decoder.h"
14 #include "quiche/quic/core/quic_error_codes.h"
15 #include "quiche/quic/test_tools/qpack/qpack_decoder_test_utils.h"
16 #include "quiche/quic/test_tools/qpack/qpack_test_utils.h"
17
18 namespace quic {
19 namespace test {
20
21 struct DecoderAndHandler {
22 std::unique_ptr<QpackProgressiveDecoder> decoder;
23 std::unique_ptr<QpackProgressiveDecoder::HeadersHandlerInterface> handler;
24 };
25
26 using DecoderAndHandlerMap = std::map<QuicStreamId, DecoderAndHandler>;
27
28 // Class that sets externally owned |error_detected| to true
29 // on encoder stream error.
30 class ErrorDelegate : public QpackDecoder::EncoderStreamErrorDelegate {
31 public:
ErrorDelegate(bool * error_detected)32 ErrorDelegate(bool* error_detected) : error_detected_(error_detected) {}
33 ~ErrorDelegate() override = default;
34
OnEncoderStreamError(QuicErrorCode,absl::string_view)35 void OnEncoderStreamError(QuicErrorCode /*error_code*/,
36 absl::string_view /*error_message*/) override {
37 *error_detected_ = true;
38 }
39
40 private:
41 bool* const error_detected_;
42 };
43
44 // Class that destroys DecoderAndHandler when decoding completes, and sets
45 // externally owned |error_detected| to true on encoder stream error.
46 class HeadersHandler : public QpackProgressiveDecoder::HeadersHandlerInterface {
47 public:
HeadersHandler(QuicStreamId stream_id,DecoderAndHandlerMap * processing_decoders,bool * error_detected)48 HeadersHandler(QuicStreamId stream_id,
49 DecoderAndHandlerMap* processing_decoders,
50 bool* error_detected)
51 : stream_id_(stream_id),
52 processing_decoders_(processing_decoders),
53 error_detected_(error_detected) {}
54 ~HeadersHandler() override = default;
55
OnHeaderDecoded(absl::string_view,absl::string_view)56 void OnHeaderDecoded(absl::string_view /*name*/,
57 absl::string_view /*value*/) override {}
58
59 // Remove DecoderAndHandler from |*processing_decoders|.
OnDecodingCompleted()60 void OnDecodingCompleted() override {
61 // Will delete |this|.
62 size_t result = processing_decoders_->erase(stream_id_);
63 QUICHE_CHECK_EQ(1u, result);
64 }
65
OnDecodingErrorDetected(QuicErrorCode,absl::string_view)66 void OnDecodingErrorDetected(QuicErrorCode /*error_code*/,
67 absl::string_view /*error_message*/) override {
68 *error_detected_ = true;
69 }
70
71 private:
72 const QuicStreamId stream_id_;
73 DecoderAndHandlerMap* const processing_decoders_;
74 bool* const error_detected_;
75 };
76
77 // This fuzzer exercises QpackDecoder. It should be able to cover all possible
78 // code paths. There is no point in encoding QpackDecoder's output to turn this
79 // into a roundtrip test, because the same header list can be encoded in many
80 // different ways, so the output could not be expected to match the original
81 // input.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)82 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
83 FuzzedDataProvider provider(data, size);
84
85 // Maximum 256 byte dynamic table. Such a small size helps test draining
86 // entries and eviction.
87 const uint64_t maximum_dynamic_table_capacity =
88 provider.ConsumeIntegral<uint8_t>();
89 // Maximum 256 blocked streams.
90 const uint64_t maximum_blocked_streams = provider.ConsumeIntegral<uint8_t>();
91
92 // |error_detected| will be set to true if an error is encountered either in a
93 // header block or on the encoder stream.
94 bool error_detected = false;
95
96 ErrorDelegate encoder_stream_error_delegate(&error_detected);
97 QpackDecoder decoder(maximum_dynamic_table_capacity, maximum_blocked_streams,
98 &encoder_stream_error_delegate);
99
100 NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
101 decoder.set_qpack_stream_sender_delegate(&decoder_stream_sender_delegate);
102
103 // Decoders still reading the header block, with corresponding handlers.
104 DecoderAndHandlerMap reading_decoders;
105
106 // Decoders still processing the completely read header block,
107 // with corresponding handlers.
108 DecoderAndHandlerMap processing_decoders;
109
110 // Maximum 256 data fragments to limit runtime and memory usage.
111 auto fragment_count = provider.ConsumeIntegral<uint8_t>();
112 while (fragment_count > 0 && !error_detected &&
113 provider.remaining_bytes() > 0) {
114 --fragment_count;
115 switch (provider.ConsumeIntegralInRange<uint8_t>(0, 3)) {
116 // Feed encoder stream data to QpackDecoder.
117 case 0: {
118 size_t fragment_size = provider.ConsumeIntegral<uint8_t>();
119 std::string encoded_data =
120 provider.ConsumeRandomLengthString(fragment_size);
121 decoder.encoder_stream_receiver()->Decode(encoded_data);
122
123 continue;
124 }
125
126 // Create new progressive decoder.
127 case 1: {
128 QuicStreamId stream_id = provider.ConsumeIntegral<uint8_t>();
129 if (reading_decoders.find(stream_id) != reading_decoders.end() ||
130 processing_decoders.find(stream_id) != processing_decoders.end()) {
131 continue;
132 }
133
134 DecoderAndHandler decoder_and_handler;
135 decoder_and_handler.handler = std::make_unique<HeadersHandler>(
136 stream_id, &processing_decoders, &error_detected);
137 decoder_and_handler.decoder = decoder.CreateProgressiveDecoder(
138 stream_id, decoder_and_handler.handler.get());
139 reading_decoders.insert({stream_id, std::move(decoder_and_handler)});
140
141 continue;
142 }
143
144 // Feed header block data to existing decoder.
145 case 2: {
146 if (reading_decoders.empty()) {
147 continue;
148 }
149
150 auto it = reading_decoders.begin();
151 auto distance = provider.ConsumeIntegralInRange<uint8_t>(
152 0, reading_decoders.size() - 1);
153 std::advance(it, distance);
154
155 size_t fragment_size = provider.ConsumeIntegral<uint8_t>();
156 std::string encoded_data =
157 provider.ConsumeRandomLengthString(fragment_size);
158 it->second.decoder->Decode(encoded_data);
159
160 continue;
161 }
162
163 // End header block.
164 case 3: {
165 if (reading_decoders.empty()) {
166 continue;
167 }
168
169 auto it = reading_decoders.begin();
170 auto distance = provider.ConsumeIntegralInRange<uint8_t>(
171 0, reading_decoders.size() - 1);
172 std::advance(it, distance);
173
174 QpackProgressiveDecoder* reading_decoder = it->second.decoder.get();
175
176 // Move DecoderAndHandler to |processing_decoders| first, because
177 // EndHeaderBlock() might synchronously call OnDecodingCompleted().
178 QuicStreamId stream_id = it->first;
179 processing_decoders.insert({stream_id, std::move(it->second)});
180 reading_decoders.erase(it);
181
182 reading_decoder->EndHeaderBlock();
183
184 continue;
185 }
186 }
187 }
188
189 return 0;
190 }
191
192 } // namespace test
193 } // namespace quic
194