xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/qpack/fuzzer/qpack_decoder_fuzzer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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