xref: /aosp_15_r20/external/grpc-grpc/test/core/transport/chttp2/hpack_parser_input_size_fuzzer.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // For all inputs, ensure parsing one byte at a time produces the same result as
16 // parsing the entire input at once.
17 
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include <limits>
23 #include <memory>
24 #include <string>
25 
26 #include "absl/cleanup/cleanup.h"
27 #include "absl/random/bit_gen_ref.h"
28 #include "absl/status/status.h"
29 #include "absl/status/statusor.h"
30 #include "absl/strings/str_cat.h"
31 
32 #include <grpc/event_engine/memory_allocator.h>
33 #include <grpc/slice.h>
34 #include <grpc/support/alloc.h>
35 #include <grpc/support/time.h>
36 
37 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
38 #include "src/core/lib/gprpp/ref_counted_ptr.h"
39 #include "src/core/lib/gprpp/status_helper.h"
40 #include "src/core/lib/iomgr/error.h"
41 #include "src/core/lib/iomgr/exec_ctx.h"
42 #include "src/core/lib/resource_quota/arena.h"
43 #include "src/core/lib/resource_quota/memory_quota.h"
44 #include "src/core/lib/resource_quota/resource_quota.h"
45 #include "src/core/lib/slice/slice.h"
46 #include "src/core/lib/transport/metadata_batch.h"
47 #include "test/core/util/slice_splitter.h"
48 
49 bool squelch = true;
50 bool leak_check = true;
51 
52 namespace grpc_core {
53 namespace {
54 
55 struct DeterministicBitGen : public std::numeric_limits<uint64_t> {
56   using result_type = uint64_t;
operator ()grpc_core::__anon160086170111::DeterministicBitGen57   uint64_t operator()() { return 42; }
58 };
59 
60 class TestEncoder {
61  public:
result()62   std::string result() { return out_; }
63 
Encode(const Slice & key,const Slice & value)64   void Encode(const Slice& key, const Slice& value) {
65     out_.append(
66         absl::StrCat(key.as_string_view(), ": ", value.as_string_view(), "\n"));
67   }
68 
69   template <typename T, typename V>
Encode(T,const V & v)70   void Encode(T, const V& v) {
71     out_.append(absl::StrCat(T::key(), ": ", T::DisplayValue(v), "\n"));
72   }
73 
74  private:
75   std::string out_;
76 };
77 
IsStreamError(const absl::Status & status)78 bool IsStreamError(const absl::Status& status) {
79   intptr_t stream_id;
80   return grpc_error_get_int(status, StatusIntProperty::kStreamId, &stream_id);
81 }
82 
TestVector(grpc_slice_split_mode mode,Slice input)83 absl::StatusOr<std::string> TestVector(grpc_slice_split_mode mode,
84                                        Slice input) {
85   MemoryAllocator memory_allocator = MemoryAllocator(
86       ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test"));
87   auto arena = MakeScopedArena(1024, &memory_allocator);
88   ExecCtx exec_ctx;
89   grpc_slice* slices;
90   size_t nslices;
91   size_t i;
92 
93   grpc_metadata_batch b;
94 
95   HPackParser parser;
96   parser.BeginFrame(
97       &b, 1024, 1024, HPackParser::Boundary::None, HPackParser::Priority::None,
98       HPackParser::LogInfo{1, HPackParser::LogInfo::kHeaders, false});
99 
100   grpc_split_slices(mode, const_cast<grpc_slice*>(&input.c_slice()), 1, &slices,
101                     &nslices);
102   auto cleanup_slices = absl::MakeCleanup([slices, nslices] {
103     for (size_t i = 0; i < nslices; i++) {
104       grpc_slice_unref(slices[i]);
105     }
106     gpr_free(slices);
107   });
108 
109   absl::Status found_err;
110   for (i = 0; i < nslices; i++) {
111     ExecCtx exec_ctx;
112     DeterministicBitGen bitgen;
113     auto err =
114         parser.Parse(slices[i], i == nslices - 1, absl::BitGenRef(bitgen),
115                      /*call_tracer=*/nullptr);
116     if (!err.ok()) {
117       if (!IsStreamError(err)) return err;
118       if (found_err.ok()) found_err = err;
119     }
120   }
121   if (!found_err.ok()) return found_err;
122 
123   TestEncoder encoder;
124   b.Encode(&encoder);
125   return encoder.result();
126 }
127 
Stringify(absl::StatusOr<std::string> result)128 std::string Stringify(absl::StatusOr<std::string> result) {
129   if (result.ok()) {
130     return absl::StrCat("OK\n", result.value());
131   } else {
132     intptr_t stream_id;
133     bool has_stream = grpc_error_get_int(
134         result.status(), StatusIntProperty::kStreamId, &stream_id);
135     return absl::StrCat(
136         has_stream ? "STREAM" : "CONNECTION", " ERROR: ",
137         result.status().ToString(absl::StatusToStringMode::kWithNoExtraData));
138   }
139 }
140 
141 }  // namespace
142 }  // namespace grpc_core
143 
144 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
145 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)146 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
147   gpr_now_impl = [](gpr_clock_type clock_type) {
148     return gpr_timespec{10, 0, clock_type};
149   };
150   auto slice = grpc_core::Slice::FromCopiedBuffer(data, size);
151   auto full = grpc_core::Stringify(
152       grpc_core::TestVector(GRPC_SLICE_SPLIT_IDENTITY, slice.Ref()));
153   auto one_byte = grpc_core::Stringify(
154       grpc_core::TestVector(GRPC_SLICE_SPLIT_ONE_BYTE, slice.Ref()));
155   if (full != one_byte) {
156     fprintf(stderr, "MISMATCHED RESULTS\nFULL SLICE: %s\nONE BYTE: %s\n",
157             full.c_str(), one_byte.c_str());
158     abort();
159   }
160   return 0;
161 }
162