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