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