1 : // Copyright 2015 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/refinery/validators/exception_handler_validator.h"
16 :
17 : #include <string>
18 :
19 : #include "base/logging.h"
20 : #include "gtest/gtest.h"
21 : #include "syzygy/minidump/minidump.h"
22 : #include "syzygy/minidump/unittest_util.h"
23 : #include "syzygy/refinery/unittest_util.h"
24 : #include "syzygy/refinery/analyzers/memory_analyzer.h"
25 : #include "syzygy/refinery/analyzers/thread_analyzer.h"
26 : #include "syzygy/refinery/process_state/process_state.h"
27 : #include "syzygy/refinery/process_state/process_state_util.h"
28 : #include "syzygy/refinery/process_state/refinery.pb.h"
29 :
30 : namespace refinery {
31 :
32 : namespace {
33 :
34 E : bool RunAnalysis(const minidump::Minidump& dump, ProcessState* process_state) {
35 E : MemoryAnalyzer memory_analyzer;
36 : if (memory_analyzer.Analyze(dump, process_state) !=
37 E : Analyzer::ANALYSIS_COMPLETE) {
38 i : return false;
39 : }
40 E : ThreadAnalyzer thread_analyzer;
41 : return thread_analyzer.Analyze(dump, process_state) ==
42 E : Analyzer::ANALYSIS_COMPLETE;
43 E : }
44 :
45 : testing::MinidumpSpecification::MemorySpecification CreateTibMemorySpec(
46 : Address tib_addr,
47 E : Address exception_registration_record_addr) {
48 E : std::string tib_buffer;
49 E : tib_buffer.resize(sizeof(NT_TIB));
50 E : NT_TIB* tib = reinterpret_cast<NT_TIB*>(&tib_buffer.at(0));
51 : tib->ExceptionList = reinterpret_cast<EXCEPTION_REGISTRATION_RECORD*>(
52 E : exception_registration_record_addr);
53 : return testing::MinidumpSpecification::MemorySpecification(tib_addr,
54 E : tib_buffer);
55 E : }
56 :
57 E : void SetExceptionRegistrationRecordNext(void* buffer, Address next_addr) {
58 : EXCEPTION_REGISTRATION_RECORD* record =
59 E : reinterpret_cast<EXCEPTION_REGISTRATION_RECORD*>(buffer);
60 E : record->Next = reinterpret_cast<EXCEPTION_REGISTRATION_RECORD*>(next_addr);
61 E : }
62 :
63 : } // namespace
64 :
65 E : TEST(ExceptionHandlerValidatorTest, AnalyzeMinidump) {
66 : // Process the minidump for memory and thread data.
67 E : ProcessState process_state;
68 :
69 E : minidump::Minidump minidump;
70 E : ASSERT_TRUE(minidump.Open(testing::TestMinidumps::GetNotepad32Dump()));
71 E : ASSERT_TRUE(RunAnalysis(minidump, &process_state));
72 :
73 : // Run the validator.
74 E : ValidationReport report;
75 E : ExceptionHandlerValidator validator;
76 : ASSERT_EQ(Validator::VALIDATION_COMPLETE,
77 E : validator.Validate(&process_state, &report));
78 E : ASSERT_EQ(0, report.error_size());
79 E : }
80 :
81 : namespace {
82 : const size_t kThreadId = 1U;
83 : const Address kStackAddr = 80ULL;
84 : const Address kStackSize = 2 * sizeof(EXCEPTION_REGISTRATION_RECORD);
85 : const Address kTebAddress = 8000ULL;
86 : } // namespace
87 :
88 : class ExceptionHandlerValidatorSyntheticTest
89 : : public testing::SyntheticMinidumpTest {
90 : protected:
91 : void PerformTest(const std::string& stack_buffer,
92 : bool include_teb,
93 : Address exception_registration_record_addr,
94 : Validator::ValidationResult expected_validation_result,
95 : bool is_violation_expected,
96 E : ViolationType expected_violation) {
97 : // Generate a synthetic minidump with a thread, as well as memory for its
98 : // stack and teb.
99 : testing::MinidumpSpecification::ThreadSpecification thread_spec(
100 E : kThreadId, kStackAddr, kStackSize);
101 E : thread_spec.SetTebAddress(kTebAddress);
102 :
103 : testing::MinidumpSpecification::MemorySpecification stack_memory_spec(
104 E : kStackAddr, stack_buffer);
105 E : testing::MinidumpSpecification spec;
106 E : ASSERT_TRUE(spec.AddMemoryRegion(stack_memory_spec));
107 :
108 E : if (include_teb) {
109 : testing::MinidumpSpecification::MemorySpecification teb_memory_spec =
110 E : CreateTibMemorySpec(kTebAddress, exception_registration_record_addr);
111 E : ASSERT_TRUE(spec.AddMemoryRegion(teb_memory_spec));
112 E : }
113 :
114 E : ASSERT_TRUE(spec.AddThread(thread_spec));
115 E : ASSERT_NO_FATAL_FAILURE(Serialize(spec));
116 :
117 : // Perform analysis and validation, then inspect the report.
118 E : ASSERT_NO_FATAL_FAILURE(Analyze());
119 E : ASSERT_EQ(expected_validation_result, Validate());
120 E : if (expected_validation_result != Validator::VALIDATION_COMPLETE) {
121 E : return;
122 : }
123 :
124 E : ASSERT_EQ(is_violation_expected ? 1 : 0, report_.error_size());
125 E : if (is_violation_expected)
126 E : ASSERT_EQ(expected_violation, report_.error(0).type());
127 E : }
128 :
129 E : void Analyze() {
130 E : minidump::Minidump minidump;
131 E : ASSERT_TRUE(minidump.Open(dump_file()));
132 E : ASSERT_TRUE(RunAnalysis(minidump, &process_state_));
133 E : }
134 :
135 E : Validator::ValidationResult Validate() {
136 E : ExceptionHandlerValidator validator;
137 E : return validator.Validate(&process_state_, &report_);
138 E : }
139 :
140 : ProcessState process_state_;
141 : ValidationReport report_;
142 : };
143 :
144 E : TEST_F(ExceptionHandlerValidatorSyntheticTest, TebNotInDumpTest) {
145 E : std::string stack_buffer;
146 E : stack_buffer.resize(kStackSize);
147 E : Address unused_addr = 0ULL;
148 : ASSERT_NO_FATAL_FAILURE(PerformTest(stack_buffer, false /* No Teb */,
149 : unused_addr, Validator::VALIDATION_ERROR,
150 E : false, VIOLATION_UNKNOWN));
151 E : }
152 :
153 : TEST_F(ExceptionHandlerValidatorSyntheticTest,
154 E : NoExceptionRegistrationRecordTest) {
155 E : std::string stack_buffer;
156 E : stack_buffer.resize(kStackSize);
157 E : Address no_exception_registration_record_addr = static_cast<Address>(-1);
158 : ASSERT_NO_FATAL_FAILURE(
159 : PerformTest(stack_buffer, true, no_exception_registration_record_addr,
160 : Validator::VALIDATION_COMPLETE, true,
161 E : VIOLATION_NO_EXCEPTION_REGISTRATION_RECORD));
162 E : }
163 :
164 : TEST_F(ExceptionHandlerValidatorSyntheticTest,
165 E : ExceptionRegistrationRecordNotInStackTest) {
166 E : std::string stack_buffer;
167 E : stack_buffer.resize(kStackSize);
168 E : Address exception_registration_record_addr = kStackAddr + kStackSize;
169 : ASSERT_NO_FATAL_FAILURE(
170 : PerformTest(stack_buffer, true, exception_registration_record_addr,
171 : Validator::VALIDATION_COMPLETE, true,
172 E : VIOLATION_EXCEPTION_REGISTRATION_RECORD_NOT_IN_STACK));
173 E : }
174 :
175 : TEST_F(ExceptionHandlerValidatorSyntheticTest,
176 E : ExceptionRegistrationRecordAddressIncreaseTest) {
177 E : std::string stack_buffer;
178 E : stack_buffer.resize(kStackSize);
179 E : size_t record_size = sizeof(EXCEPTION_REGISTRATION_RECORD);
180 : SetExceptionRegistrationRecordNext(&stack_buffer.at(0),
181 E : static_cast<Address>(-1));
182 E : SetExceptionRegistrationRecordNext(&stack_buffer.at(record_size), kStackAddr);
183 :
184 E : Address exception_registration_record_addr = kStackAddr + record_size;
185 : ASSERT_NO_FATAL_FAILURE(
186 : PerformTest(stack_buffer, true, exception_registration_record_addr,
187 : Validator::VALIDATION_COMPLETE, true,
188 E : VIOLATION_EXCEPTION_CHAIN_ADDRESS_DECREASE));
189 E : }
190 :
191 E : TEST_F(ExceptionHandlerValidatorSyntheticTest, BasicTest) {
192 E : std::string stack_buffer;
193 E : stack_buffer.resize(kStackSize);
194 E : size_t record_size = sizeof(EXCEPTION_REGISTRATION_RECORD);
195 : SetExceptionRegistrationRecordNext(&stack_buffer.at(0),
196 E : kStackAddr + record_size);
197 : SetExceptionRegistrationRecordNext(&stack_buffer.at(record_size),
198 E : static_cast<Address>(-1));
199 :
200 E : Address exception_registration_record_addr = kStackAddr;
201 : ASSERT_NO_FATAL_FAILURE(
202 : PerformTest(stack_buffer, true, exception_registration_record_addr,
203 E : Validator::VALIDATION_COMPLETE, false, VIOLATION_UNKNOWN));
204 E : }
205 :
206 : } // namespace refinery
|