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 <grpc/event_engine/memory_allocator.h>
19 #include <grpc/slice.h>
20 #include <grpc/support/alloc.h>
21 #include <grpc/support/time.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include <limits>
27 #include <memory>
28 #include <string>
29
30 #include "absl/cleanup/cleanup.h"
31 #include "absl/random/bit_gen_ref.h"
32 #include "absl/status/status.h"
33 #include "absl/status/statusor.h"
34 #include "absl/strings/str_cat.h"
35 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
36 #include "src/core/lib/iomgr/error.h"
37 #include "src/core/lib/iomgr/exec_ctx.h"
38 #include "src/core/lib/resource_quota/arena.h"
39 #include "src/core/lib/resource_quota/memory_quota.h"
40 #include "src/core/lib/resource_quota/resource_quota.h"
41 #include "src/core/lib/slice/slice.h"
42 #include "src/core/lib/transport/metadata_batch.h"
43 #include "src/core/util/ref_counted_ptr.h"
44 #include "src/core/util/status_helper.h"
45 #include "test/core/test_util/slice_splitter.h"
46
47 bool squelch = true;
48 bool leak_check = true;
49
50 namespace grpc_core {
51 namespace {
52
53 struct DeterministicBitGen : public std::numeric_limits<uint64_t> {
54 using result_type = uint64_t;
operator ()grpc_core::__anond04c6d5b0111::DeterministicBitGen55 uint64_t operator()() { return 42; }
56 };
57
58 class TestEncoder {
59 public:
result()60 std::string result() { return out_; }
61
Encode(const Slice & key,const Slice & value)62 void Encode(const Slice& key, const Slice& value) {
63 out_.append(
64 absl::StrCat(key.as_string_view(), ": ", value.as_string_view(), "\n"));
65 }
66
67 template <typename T, typename V>
Encode(T,const V & v)68 void Encode(T, const V& v) {
69 out_.append(absl::StrCat(T::key(), ": ", T::DisplayValue(v), "\n"));
70 }
71
72 private:
73 std::string out_;
74 };
75
IsStreamError(const absl::Status & status)76 bool IsStreamError(const absl::Status& status) {
77 intptr_t stream_id;
78 return grpc_error_get_int(status, StatusIntProperty::kStreamId, &stream_id);
79 }
80
TestVector(grpc_slice_split_mode mode,Slice input)81 absl::StatusOr<std::string> TestVector(grpc_slice_split_mode mode,
82 Slice input) {
83 auto arena = SimpleArenaAllocator()->MakeArena();
84 ExecCtx exec_ctx;
85 grpc_slice* slices;
86 size_t nslices;
87 size_t i;
88
89 grpc_metadata_batch b;
90
91 HPackParser parser;
92 parser.BeginFrame(
93 &b, 1024, 1024, HPackParser::Boundary::None, HPackParser::Priority::None,
94 HPackParser::LogInfo{1, HPackParser::LogInfo::kHeaders, false});
95
96 grpc_split_slices(mode, const_cast<grpc_slice*>(&input.c_slice()), 1, &slices,
97 &nslices);
98 auto cleanup_slices = absl::MakeCleanup([slices, nslices] {
99 for (size_t i = 0; i < nslices; i++) {
100 grpc_slice_unref(slices[i]);
101 }
102 gpr_free(slices);
103 });
104
105 absl::Status found_err;
106 for (i = 0; i < nslices; i++) {
107 ExecCtx exec_ctx;
108 DeterministicBitGen bitgen;
109 auto err =
110 parser.Parse(slices[i], i == nslices - 1, absl::BitGenRef(bitgen),
111 /*call_tracer=*/nullptr);
112 if (!err.ok()) {
113 if (!IsStreamError(err)) return err;
114 if (found_err.ok()) found_err = err;
115 }
116 }
117 if (!found_err.ok()) return found_err;
118
119 TestEncoder encoder;
120 b.Encode(&encoder);
121 return encoder.result();
122 }
123
Stringify(absl::StatusOr<std::string> result)124 std::string Stringify(absl::StatusOr<std::string> result) {
125 if (result.ok()) {
126 return absl::StrCat("OK\n", result.value());
127 } else {
128 intptr_t stream_id;
129 bool has_stream = grpc_error_get_int(
130 result.status(), StatusIntProperty::kStreamId, &stream_id);
131 return absl::StrCat(
132 has_stream ? "STREAM" : "CONNECTION", " ERROR: ",
133 result.status().ToString(absl::StatusToStringMode::kWithNoExtraData));
134 }
135 }
136
137 } // namespace
138 } // namespace grpc_core
139
140 extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
141
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)142 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
143 gpr_now_impl = [](gpr_clock_type clock_type) {
144 return gpr_timespec{10, 0, clock_type};
145 };
146 auto slice = grpc_core::Slice::FromCopiedBuffer(data, size);
147 auto full = grpc_core::Stringify(
148 grpc_core::TestVector(GRPC_SLICE_SPLIT_IDENTITY, slice.Ref()));
149 auto one_byte = grpc_core::Stringify(
150 grpc_core::TestVector(GRPC_SLICE_SPLIT_ONE_BYTE, slice.Ref()));
151 if (full != one_byte) {
152 fprintf(stderr, "MISMATCHED RESULTS\nFULL SLICE: %s\nONE BYTE: %s\n",
153 full.c_str(), one_byte.c_str());
154 abort();
155 }
156 return 0;
157 }
158