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