xref: /aosp_15_r20/external/cronet/net/spdy/fuzzing/hpack_fuzz_util.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_SPDY_FUZZING_HPACK_FUZZ_UTIL_H_
6 #define NET_SPDY_FUZZING_HPACK_FUZZ_UTIL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <memory>
12 #include <vector>
13 
14 #include "base/containers/span.h"
15 #include "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_decoder_adapter.h"
16 #include "net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_encoder.h"
17 #include "net/third_party/quiche/src/quiche/spdy/core/recording_headers_handler.h"
18 
19 namespace spdy {
20 
21 class HpackFuzzUtil {
22  public:
23   // A GeneratorContext holds ordered header names & values which are
24   // initially seeded and then expanded with dynamically generated data.
25   struct GeneratorContext {
26     GeneratorContext();
27     ~GeneratorContext();
28     std::vector<std::string> names;
29     std::vector<std::string> values;
30   };
31 
32   // Initializes a GeneratorContext with a random seed and name/value fixtures.
33   static void InitializeGeneratorContext(GeneratorContext* context);
34 
35   // Generates a header set from the generator context.
36   static Http2HeaderBlock NextGeneratedHeaderSet(GeneratorContext* context);
37 
38   // Samples a size from the exponential distribution with mean |mean|,
39   // upper-bounded by |sanity_bound|.
40   static size_t SampleExponential(size_t mean, size_t sanity_bound);
41 
42   // Holds an input string, and manages an offset into that string.
43   struct Input {
44     Input();  // Initializes |offset| to zero.
45     ~Input();
46 
47     // Returns a span over the next `bytes` many characters in the buffer, and
48     // advances the buffer offset past them.
ReadSpanInput49     base::span<const uint8_t> ReadSpan(size_t bytes) {
50       auto out = RemainingBytes().first(bytes);
51       offset += bytes;
52       return out;
53     }
54     // Returns a span over the next `bytes` many characters in the buffer, and
55     // advances the buffer offset past them.
56     //
57     // This version takes a compile-time size and returns a fixed-size span.
58     template <size_t bytes>
ReadSpanInput59     base::span<const uint8_t, bytes> ReadSpan() {
60       auto out = RemainingBytes().first<bytes>();
61       offset += bytes;
62       return out;
63     }
64 
65     // Returns a span over all remaining bytes in the input buffer.
RemainingBytesInput66     base::span<const uint8_t> RemainingBytes() {
67       return base::as_byte_span(input).subspan(offset);
68     }
69 
70     std::string input;
71     size_t offset = 0;
72   };
73 
74   // Returns true if the next header block was set at |out|. Returns
75   // false if no input header blocks remain.
76   static bool NextHeaderBlock(Input* input, std::string_view* out);
77 
78   // Returns the serialized header block length prefix for a block of
79   // |block_size| bytes.
80   static std::string HeaderBlockPrefix(size_t block_size);
81 
82   // A FuzzerContext holds fuzzer input, as well as each of the decoder and
83   // encoder stages which fuzzed header blocks are processed through.
84   struct FuzzerContext {
85     FuzzerContext();
86     ~FuzzerContext();
87     std::unique_ptr<HpackDecoderAdapter> first_stage;
88     std::unique_ptr<RecordingHeadersHandler> first_stage_handler;
89     std::unique_ptr<HpackEncoder> second_stage;
90     std::unique_ptr<HpackDecoderAdapter> third_stage;
91     std::unique_ptr<RecordingHeadersHandler> third_stage_handler;
92   };
93 
94   static void InitializeFuzzerContext(FuzzerContext* context);
95 
96   // Runs |input_block| through |first_stage| and, iff that succeeds,
97   // |second_stage| and |third_stage| as well. Returns whether all stages
98   // processed the input without error.
99   static bool RunHeaderBlockThroughFuzzerStages(FuzzerContext* context,
100                                                 std::string_view input_block);
101 
102   // Flips random bits within |buffer|. The total number of flips is
103   // |flip_per_thousand| bits for every 1,024 bytes of |buffer_length|,
104   // rounding up.
105   static void FlipBits(uint8_t* buffer,
106                        size_t buffer_length,
107                        size_t flip_per_thousand);
108 };
109 
110 }  // namespace spdy
111 
112 #endif  // NET_SPDY_FUZZING_HPACK_FUZZ_UTIL_H_
113