1 : // Copyright 2013 Google Inc. All Rights Reserved.
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 : #include "syzygy/genfilter/filter_compiler.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/common/unittest_util.h"
20 : #include "syzygy/core/unittest_util.h"
21 : #include "syzygy/pe/unittest_util.h"
22 :
23 : namespace genfilter {
24 :
25 : namespace {
26 :
27 : class TestFilterCompiler : public FilterCompiler {
28 : public:
29 : using FilterCompiler::Rule;
30 : using FilterCompiler::RuleMap;
31 : using FilterCompiler::RulePointers;
32 :
33 : using FilterCompiler::rule_map_;
34 : using FilterCompiler::rules_by_type_;
35 :
36 E : TestFilterCompiler() { }
37 :
38 : // Returns the |index|th rule.
39 E : const Rule& rule(size_t index) const {
40 E : RuleMap::const_iterator it = rule_map_.find(index);
41 E : return it->second;
42 E : }
43 : };
44 :
45 : class FilterCompilerTest : public testing::PELibUnitTest {
46 : public:
47 : typedef testing::PELibUnitTest Super;
48 :
49 E : virtual void SetUp() override {
50 E : Super::SetUp();
51 E : ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_));
52 E : test_dll_ = testing::GetExeRelativePath(testing::kTestDllName);
53 E : test_dll_pdb_ = testing::GetOutputRelativePath(testing::kTestDllPdbName);
54 E : dummy_dll_ = testing::GetExeRelativePath(L"this-does-not-exist.dll");
55 E : dummy_pdb_ = testing::GetExeRelativePath(L"this-does-not-exist.pdb");
56 : mismatched_test_dll_pdb_ =
57 E : testing::GetSrcRelativePath(L"pe\\test_data\\test_dll.pdb");
58 E : filter_txt_ = temp_dir_.Append(L"filter.txt");
59 E : }
60 :
61 E : virtual void TearDown() override {
62 E : ASSERT_TRUE(base::DeleteFile(temp_dir_, true));
63 E : Super::TearDown();
64 E : }
65 :
66 E : void CreateFilterDescriptionFile(const base::StringPiece& line) {
67 E : base::ScopedFILE file(base::OpenFile(filter_txt_, "wb"));
68 E : ::fprintf(file.get(), "%.*s\n", line.length(), line.data());
69 E : }
70 :
71 E : void CreateFilterDescriptionFile() {
72 E : base::ScopedFILE file(base::OpenFile(filter_txt_, "wb"));
73 E : ::fprintf(file.get(), "# This is a comment.\n");
74 E : ::fprintf(file.get(), "\n");
75 E : ::fprintf(file.get(), "+function:DllMain # Another comment.\n");
76 E : ::fprintf(file.get(), " + function : ThisFunctionDoesNotExist \n");
77 E : ::fprintf(file.get(), "-public_symbol:\\?function1.*\n");
78 E : }
79 :
80 : // A temporary folder for holding filter files, etc.
81 : base::FilePath temp_dir_;
82 :
83 : // A handful of paths.
84 : base::FilePath test_dll_;
85 : base::FilePath test_dll_pdb_;
86 : base::FilePath dummy_dll_;
87 : base::FilePath dummy_pdb_;
88 : base::FilePath mismatched_test_dll_pdb_;
89 : base::FilePath filter_txt_;
90 : };
91 :
92 : } // namespace
93 :
94 E : TEST_F(FilterCompilerTest, Constructor) {
95 E : TestFilterCompiler fc;
96 E : EXPECT_TRUE(fc.image_path().empty());
97 E : EXPECT_TRUE(fc.pdb_path().empty());
98 E : EXPECT_TRUE(fc.rule_map_.empty());
99 E : for (size_t i = 0; i < arraysize(fc.rules_by_type_); ++i) {
100 E : EXPECT_TRUE(fc.rules_by_type_[i].empty());
101 E : }
102 E : }
103 :
104 E : TEST_F(FilterCompilerTest, InitFailsInvalidPePath) {
105 E : DisableLogging();
106 :
107 E : TestFilterCompiler fc1;
108 E : EXPECT_FALSE(fc1.Init(dummy_dll_));
109 :
110 E : TestFilterCompiler fc2;
111 E : EXPECT_FALSE(fc2.Init(dummy_dll_, base::FilePath()));
112 E : }
113 :
114 E : TEST_F(FilterCompilerTest, InitFailsInvalidPdbPath) {
115 E : DisableLogging();
116 :
117 E : TestFilterCompiler fc;
118 E : EXPECT_FALSE(fc.Init(test_dll_, dummy_pdb_));
119 E : }
120 :
121 E : TEST_F(FilterCompilerTest, InitFailsMismatchedPeAndPdb) {
122 E : DisableLogging();
123 :
124 E : TestFilterCompiler fc;
125 E : EXPECT_FALSE(fc.Init(test_dll_, mismatched_test_dll_pdb_));
126 E : }
127 :
128 E : TEST_F(FilterCompilerTest, InitSucceedsSpecifiedPdb) {
129 E : TestFilterCompiler fc;
130 E : EXPECT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
131 E : EXPECT_EQ(test_dll_, fc.image_path());
132 E : EXPECT_EQ(test_dll_pdb_, fc.pdb_path());
133 E : }
134 :
135 E : TEST_F(FilterCompilerTest, InitSucceedsSearchForPdb) {
136 E : TestFilterCompiler fc1;
137 E : EXPECT_TRUE(fc1.Init(test_dll_));
138 E : EXPECT_EQ(test_dll_, fc1.image_path());
139 E : EXPECT_SAME_FILE(test_dll_pdb_, fc1.pdb_path());
140 :
141 E : TestFilterCompiler fc2;
142 E : EXPECT_TRUE(fc2.Init(test_dll_, base::FilePath()));
143 E : EXPECT_EQ(test_dll_, fc2.image_path());
144 E : EXPECT_SAME_FILE(test_dll_pdb_, fc2.pdb_path());
145 E : }
146 :
147 E : TEST_F(FilterCompilerTest, AddRule) {
148 E : DisableLogging();
149 :
150 E : TestFilterCompiler fc;
151 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
152 E : EXPECT_EQ(0u, fc.rule_map_.size());
153 E : EXPECT_EQ(0u, fc.rules_by_type_[FilterCompiler::kFunctionRule].size());
154 E : EXPECT_EQ(0u, fc.rules_by_type_[FilterCompiler::kPublicSymbolRule].size());
155 :
156 : EXPECT_FALSE(fc.AddRule(FilterCompiler::kAddToFilter,
157 : FilterCompiler::kFunctionRule,
158 E : "broken(regex[foo"));
159 :
160 : EXPECT_TRUE(fc.AddRule(FilterCompiler::kAddToFilter,
161 : FilterCompiler::kFunctionRule,
162 E : "foo"));
163 E : EXPECT_EQ(1u, fc.rule_map_.size());
164 E : EXPECT_EQ(1u, fc.rules_by_type_[FilterCompiler::kFunctionRule].size());
165 E : EXPECT_EQ(0u, fc.rules_by_type_[FilterCompiler::kPublicSymbolRule].size());
166 :
167 : EXPECT_TRUE(fc.AddRule(FilterCompiler::kSubtractFromFilter,
168 : FilterCompiler::kPublicSymbolRule,
169 E : "bar"));
170 E : EXPECT_EQ(2u, fc.rule_map_.size());
171 E : EXPECT_EQ(1u, fc.rules_by_type_[FilterCompiler::kFunctionRule].size());
172 E : EXPECT_EQ(1u, fc.rules_by_type_[FilterCompiler::kPublicSymbolRule].size());
173 E : }
174 :
175 E : TEST_F(FilterCompilerTest, ParseFilterDescriptionFileMissingFile) {
176 E : DisableLogging();
177 :
178 E : TestFilterCompiler fc;
179 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
180 :
181 E : EXPECT_FALSE(fc.ParseFilterDescriptionFile(filter_txt_));
182 E : }
183 :
184 E : TEST_F(FilterCompilerTest, ParseFilterDescriptionFileBadModificationType) {
185 E : DisableLogging();
186 :
187 E : ASSERT_NO_FATAL_FAILURE(CreateFilterDescriptionFile("?function:foo"));
188 :
189 E : TestFilterCompiler fc;
190 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
191 :
192 E : EXPECT_FALSE(fc.ParseFilterDescriptionFile(filter_txt_));
193 E : }
194 :
195 E : TEST_F(FilterCompilerTest, ParseFilterDescriptionFileBadRuleType) {
196 E : DisableLogging();
197 :
198 : ASSERT_NO_FATAL_FAILURE(CreateFilterDescriptionFile(
199 E : "+invalid_type:foo"));
200 :
201 E : TestFilterCompiler fc;
202 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
203 :
204 E : EXPECT_FALSE(fc.ParseFilterDescriptionFile(filter_txt_));
205 E : }
206 :
207 E : TEST_F(FilterCompilerTest, ParseFilterDescriptionFileBadRegex) {
208 E : DisableLogging();
209 :
210 : ASSERT_NO_FATAL_FAILURE(CreateFilterDescriptionFile(
211 E : "+function:broken(regex[ab"));
212 :
213 E : TestFilterCompiler fc;
214 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
215 :
216 E : EXPECT_FALSE(fc.ParseFilterDescriptionFile(filter_txt_));
217 E : }
218 :
219 E : TEST_F(FilterCompilerTest, ParseFilterDescriptionFileSucceeds) {
220 E : ASSERT_NO_FATAL_FAILURE(CreateFilterDescriptionFile());
221 :
222 E : TestFilterCompiler fc;
223 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
224 :
225 E : ASSERT_TRUE(fc.ParseFilterDescriptionFile(filter_txt_));
226 E : EXPECT_EQ(3u, fc.rule_map_.size());
227 E : EXPECT_EQ(FilterCompiler::kFunctionRule, fc.rule(0).rule_type);
228 E : EXPECT_EQ(FilterCompiler::kFunctionRule, fc.rule(1).rule_type);
229 E : EXPECT_EQ(FilterCompiler::kPublicSymbolRule, fc.rule(2).rule_type);
230 E : EXPECT_EQ(FilterCompiler::kAddToFilter, fc.rule(0).modification_type);
231 E : EXPECT_EQ(FilterCompiler::kAddToFilter, fc.rule(1).modification_type);
232 E : EXPECT_EQ(FilterCompiler::kSubtractFromFilter, fc.rule(2).modification_type);
233 E : }
234 :
235 E : TEST_F(FilterCompilerTest, Compile) {
236 E : ASSERT_NO_FATAL_FAILURE(CreateFilterDescriptionFile());
237 :
238 E : TestFilterCompiler fc;
239 E : ASSERT_TRUE(fc.Init(test_dll_, test_dll_pdb_));
240 E : ASSERT_TRUE(fc.ParseFilterDescriptionFile(filter_txt_));
241 E : ASSERT_EQ(3u, fc.rule_map_.size()); // Three rules should have been parsed.
242 :
243 E : pe::ImageFilter filter;
244 E : EXPECT_TRUE(fc.Compile(&filter));
245 :
246 : // The first and last rules should have matched actual symbol info.
247 E : EXPECT_EQ(1u, fc.rule(0).ranges.size());
248 E : EXPECT_EQ(0u, fc.rule(1).ranges.size());
249 E : EXPECT_EQ(1u, fc.rule(2).ranges.size());
250 :
251 : // The image filter should be non-empty.
252 E : EXPECT_LT(0u, filter.filter.size());
253 E : }
254 :
255 : } // namespace genfilter
|