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 #include "net/spdy/fuzzing/hpack_fuzz_util.h"
6
7 #include <map>
8
9 #include "base/base_paths.h"
10 #include "base/files/file.h"
11 #include "base/files/file_util.h"
12 #include "base/path_service.h"
13 #include "net/base/hex_utils.h"
14 #include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace spdy::test {
19
20 using quiche::HttpHeaderBlock;
21 using std::map;
22
TEST(HpackFuzzUtilTest,GeneratorContextInitialization)23 TEST(HpackFuzzUtilTest, GeneratorContextInitialization) {
24 HpackFuzzUtil::GeneratorContext context;
25 HpackFuzzUtil::InitializeGeneratorContext(&context);
26
27 // Context was seeded with initial name & value fixtures.
28 EXPECT_LT(0u, context.names.size());
29 EXPECT_LT(0u, context.values.size());
30 }
31
TEST(HpackFuzzUtil,GeneratorContextExpansion)32 TEST(HpackFuzzUtil, GeneratorContextExpansion) {
33 HpackFuzzUtil::GeneratorContext context;
34
35 HttpHeaderBlock headers = HpackFuzzUtil::NextGeneratedHeaderSet(&context);
36
37 // Headers were generated, and the generator context was expanded.
38 EXPECT_LT(0u, headers.size());
39 EXPECT_LT(0u, context.names.size());
40 EXPECT_LT(0u, context.values.size());
41 }
42
43 // TODO(jgraettinger): A better test would mock a random generator and
44 // evaluate SampleExponential along fixed points of the [0,1] domain.
TEST(HpackFuzzUtilTest,SampleExponentialRegression)45 TEST(HpackFuzzUtilTest, SampleExponentialRegression) {
46 // TODO(jgraettinger): Upstream uses a seeded random generator here to pin
47 // the behavior of SampleExponential. Chromium's random generation utilities
48 // are strongly secure, but provide no way to seed the generator.
49 for (size_t i = 0; i != 100; ++i) {
50 EXPECT_GE(30u, HpackFuzzUtil::SampleExponential(10, 30));
51 }
52 }
53
TEST(HpackFuzzUtilTest,ParsesSequenceOfHeaderBlocks)54 TEST(HpackFuzzUtilTest, ParsesSequenceOfHeaderBlocks) {
55 char fixture[] =
56 "\x00\x00\x00\x05"
57 "aaaaa"
58 "\x00\x00\x00\x04"
59 "bbbb"
60 "\x00\x00\x00\x03"
61 "ccc"
62 "\x00\x00\x00\x02"
63 "dd"
64 "\x00\x00\x00\x01"
65 "e"
66 "\x00\x00\x00\x00"
67 ""
68 "\x00\x00\x00\x03"
69 "fin";
70
71 HpackFuzzUtil::Input input;
72 input.input.assign(fixture, std::size(fixture) - 1);
73
74 std::string_view block;
75
76 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
77 EXPECT_EQ("aaaaa", block);
78 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
79 EXPECT_EQ("bbbb", block);
80 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
81 EXPECT_EQ("ccc", block);
82 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
83 EXPECT_EQ("dd", block);
84 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
85 EXPECT_EQ("e", block);
86 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
87 EXPECT_EQ("", block);
88 EXPECT_TRUE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
89 EXPECT_EQ("fin", block);
90 EXPECT_FALSE(HpackFuzzUtil::NextHeaderBlock(&input, &block));
91 }
92
TEST(HpackFuzzUtilTest,SerializedHeaderBlockPrefixes)93 TEST(HpackFuzzUtilTest, SerializedHeaderBlockPrefixes) {
94 EXPECT_EQ(std::string("\x00\x00\x00\x00", 4),
95 HpackFuzzUtil::HeaderBlockPrefix(0));
96 EXPECT_EQ(std::string("\x00\x00\x00\x05", 4),
97 HpackFuzzUtil::HeaderBlockPrefix(5));
98 EXPECT_EQ("\x4f\xb3\x0a\x91", HpackFuzzUtil::HeaderBlockPrefix(1337133713));
99 }
100
TEST(HpackFuzzUtilTest,PassValidInputThroughAllStages)101 TEST(HpackFuzzUtilTest, PassValidInputThroughAllStages) {
102 // Example lifted from HpackDecoderTest.SectionD4RequestHuffmanExamples.
103 std::string input = net::HexDecode("828684418cf1e3c2e5f23a6ba0ab90f4ff");
104
105 HpackFuzzUtil::FuzzerContext context;
106 HpackFuzzUtil::InitializeFuzzerContext(&context);
107
108 EXPECT_TRUE(
109 HpackFuzzUtil::RunHeaderBlockThroughFuzzerStages(&context, input));
110
111 HttpHeaderBlock expect;
112 expect[":method"] = "GET";
113 expect[":scheme"] = "http";
114 expect[":path"] = "/";
115 expect[":authority"] = "www.example.com";
116 EXPECT_EQ(expect, context.third_stage_handler->decoded_block());
117 }
118
TEST(HpackFuzzUtilTest,ValidFuzzExamplesRegressionTest)119 TEST(HpackFuzzUtilTest, ValidFuzzExamplesRegressionTest) {
120 base::FilePath source_root;
121 ASSERT_TRUE(
122 base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &source_root));
123
124 // Load the example fixtures versioned with the source tree.
125 HpackFuzzUtil::Input input;
126 ASSERT_TRUE(base::ReadFileToString(
127 source_root.Append(FILE_PATH_LITERAL("net"))
128 .Append(FILE_PATH_LITERAL("data"))
129 .Append(FILE_PATH_LITERAL("spdy_tests"))
130 .Append(FILE_PATH_LITERAL("examples_07.hpack")),
131 &input.input));
132
133 HpackFuzzUtil::FuzzerContext context;
134 HpackFuzzUtil::InitializeFuzzerContext(&context);
135
136 std::string_view block;
137 while (HpackFuzzUtil::NextHeaderBlock(&input, &block)) {
138 // As these are valid examples, all fuzz stages should succeed.
139 EXPECT_TRUE(
140 HpackFuzzUtil::RunHeaderBlockThroughFuzzerStages(&context, block));
141 }
142 }
143
TEST(HpackFuzzUtilTest,FlipBitsMutatesBuffer)144 TEST(HpackFuzzUtilTest, FlipBitsMutatesBuffer) {
145 char buffer[] = "testbuffer1234567890";
146 std::string unmodified(buffer, std::size(buffer) - 1);
147
148 EXPECT_EQ(unmodified, buffer);
149 HpackFuzzUtil::FlipBits(reinterpret_cast<uint8_t*>(buffer),
150 std::size(buffer) - 1, 1);
151 EXPECT_NE(unmodified, buffer);
152 }
153
154 } // namespace spdy::test
155