• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/http2/core/recording_headers_handler.h"
16 #include "net/third_party/quiche/src/quiche/http2/hpack/hpack_decoder_adapter.h"
17 #include "net/third_party/quiche/src/quiche/http2/hpack/hpack_encoder.h"
18 
19 namespace quiche {
20 class HttpHeaderBlock;
21 }
22 
23 namespace spdy {
24 
25 class HpackFuzzUtil {
26  public:
27   // A GeneratorContext holds ordered header names & values which are
28   // initially seeded and then expanded with dynamically generated data.
29   struct GeneratorContext {
30     GeneratorContext();
31     ~GeneratorContext();
32     std::vector<std::string> names;
33     std::vector<std::string> values;
34   };
35 
36   // Initializes a GeneratorContext with a random seed and name/value fixtures.
37   static void InitializeGeneratorContext(GeneratorContext* context);
38 
39   // Generates a header set from the generator context.
40   static quiche::HttpHeaderBlock NextGeneratedHeaderSet(
41       GeneratorContext* context);
42 
43   // Samples a size from the exponential distribution with mean |mean|,
44   // upper-bounded by |sanity_bound|.
45   static size_t SampleExponential(size_t mean, size_t sanity_bound);
46 
47   // Holds an input string, and manages an offset into that string.
48   struct Input {
49     Input();  // Initializes |offset| to zero.
50     ~Input();
51 
52     // Returns a span over the next `bytes` many characters in the buffer, and
53     // advances the buffer offset past them.
ReadSpanInput54     base::span<const uint8_t> ReadSpan(size_t bytes) {
55       auto out = RemainingBytes().first(bytes);
56       offset += bytes;
57       return out;
58     }
59     // Returns a span over the next `bytes` many characters in the buffer, and
60     // advances the buffer offset past them.
61     //
62     // This version takes a compile-time size and returns a fixed-size span.
63     template <size_t bytes>
ReadSpanInput64     base::span<const uint8_t, bytes> ReadSpan() {
65       auto out = RemainingBytes().first<bytes>();
66       offset += bytes;
67       return out;
68     }
69 
70     // Returns a span over all remaining bytes in the input buffer.
RemainingBytesInput71     base::span<const uint8_t> RemainingBytes() {
72       return base::as_byte_span(input).subspan(offset);
73     }
74 
75     std::string input;
76     size_t offset = 0;
77   };
78 
79   // Returns true if the next header block was set at |out|. Returns
80   // false if no input header blocks remain.
81   static bool NextHeaderBlock(Input* input, std::string_view* out);
82 
83   // Returns the serialized header block length prefix for a block of
84   // |block_size| bytes.
85   static std::string HeaderBlockPrefix(size_t block_size);
86 
87   // A FuzzerContext holds fuzzer input, as well as each of the decoder and
88   // encoder stages which fuzzed header blocks are processed through.
89   struct FuzzerContext {
90     FuzzerContext();
91     ~FuzzerContext();
92     std::unique_ptr<HpackDecoderAdapter> first_stage;
93     std::unique_ptr<RecordingHeadersHandler> first_stage_handler;
94     std::unique_ptr<HpackEncoder> second_stage;
95     std::unique_ptr<HpackDecoderAdapter> third_stage;
96     std::unique_ptr<RecordingHeadersHandler> third_stage_handler;
97   };
98 
99   static void InitializeFuzzerContext(FuzzerContext* context);
100 
101   // Runs |input_block| through |first_stage| and, iff that succeeds,
102   // |second_stage| and |third_stage| as well. Returns whether all stages
103   // processed the input without error.
104   static bool RunHeaderBlockThroughFuzzerStages(FuzzerContext* context,
105                                                 std::string_view input_block);
106 
107   // Flips random bits within |buffer|. The total number of flips is
108   // |flip_per_thousand| bits for every 1,024 bytes of |buffer_length|,
109   // rounding up.
110   static void FlipBits(uint8_t* buffer,
111                        size_t buffer_length,
112                        size_t flip_per_thousand);
113 };
114 
115 }  // namespace spdy
116 
117 #endif  // NET_SPDY_FUZZING_HPACK_FUZZ_UTIL_H_
118