OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | |
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 <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include "sandbox/win/src/policy_engine_opcodes.h" | |
9 #include "sandbox/win/src/policy_engine_params.h" | |
10 #include "sandbox/win/src/sandbox_nt_types.h" | |
11 #include "sandbox/win/src/sandbox_types.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 | |
15 #define INIT_GLOBAL_RTL(member) \ | |
16 g_nt.member = reinterpret_cast<member##Function>( \ | |
17 ::GetProcAddress(ntdll, #member)); \ | |
18 if (NULL == g_nt.member) \ | |
19 return false | |
20 | |
21 namespace sandbox { | |
22 | |
23 const size_t kOpcodeMemory = 1024; | |
24 | |
25 SANDBOX_INTERCEPT NtExports g_nt; | |
26 | |
27 bool SetupNtdllImports() { | |
28 HMODULE ntdll = ::GetModuleHandle(kNtdllName); | |
29 | |
30 INIT_GLOBAL_RTL(RtlAllocateHeap); | |
31 INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString); | |
32 INIT_GLOBAL_RTL(RtlCompareUnicodeString); | |
33 INIT_GLOBAL_RTL(RtlCreateHeap); | |
34 INIT_GLOBAL_RTL(RtlDestroyHeap); | |
35 INIT_GLOBAL_RTL(RtlFreeHeap); | |
36 INIT_GLOBAL_RTL(_strnicmp); | |
37 INIT_GLOBAL_RTL(strlen); | |
38 INIT_GLOBAL_RTL(wcslen); | |
39 | |
40 return true; | |
41 } | |
42 | |
43 TEST(PolicyEngineTest, ParameterSetTest) { | |
44 void* pv1 = reinterpret_cast<void*>(0x477EAA5); | |
45 const void* pv2 = reinterpret_cast<void*>(0x987654); | |
46 ParameterSet pset1 = ParamPickerMake(pv1); | |
47 ParameterSet pset2 = ParamPickerMake(pv2); | |
48 | |
49 // Test that we can store and retrieve a void pointer: | |
50 const void* result1 =0; | |
51 uint32_t result2 = 0; | |
52 EXPECT_TRUE(pset1.Get(&result1)); | |
53 EXPECT_TRUE(pv1 == result1); | |
54 EXPECT_FALSE(pset1.Get(&result2)); | |
55 EXPECT_TRUE(pset2.Get(&result1)); | |
56 EXPECT_TRUE(pv2 == result1); | |
57 EXPECT_FALSE(pset2.Get(&result2)); | |
58 | |
59 // Test that we can store and retrieve a uint32_t: | |
60 uint32_t number = 12747; | |
61 ParameterSet pset3 = ParamPickerMake(number); | |
62 EXPECT_FALSE(pset3.Get(&result1)); | |
63 EXPECT_TRUE(pset3.Get(&result2)); | |
64 EXPECT_EQ(number, result2); | |
65 | |
66 // Test that we can store and retrieve a string: | |
67 const wchar_t* txt = L"S231L"; | |
68 ParameterSet pset4 = ParamPickerMake(txt); | |
69 const wchar_t* result3 = NULL; | |
70 EXPECT_TRUE(pset4.Get(&result3)); | |
71 EXPECT_EQ(0, wcscmp(txt, result3)); | |
72 } | |
73 | |
74 TEST(PolicyEngineTest, OpcodeConstraints) { | |
75 // Test that PolicyOpcode has no virtual functions | |
76 // because these objects are copied over to other processes | |
77 // so they cannot have vtables. | |
78 EXPECT_FALSE(__is_polymorphic(PolicyOpcode)); | |
79 // Keep developers from adding smarts to the opcodes which should | |
80 // be pretty much a bag of bytes with a OO interface. | |
81 EXPECT_TRUE(__has_trivial_destructor(PolicyOpcode)); | |
82 EXPECT_TRUE(__has_trivial_constructor(PolicyOpcode)); | |
83 EXPECT_TRUE(__has_trivial_copy(PolicyOpcode)); | |
84 } | |
85 | |
86 TEST(PolicyEngineTest, TrueFalseOpcodes) { | |
87 void* dummy = NULL; | |
88 ParameterSet ppb1 = ParamPickerMake(dummy); | |
89 char memory[kOpcodeMemory]; | |
90 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
91 | |
92 // This opcode always evaluates to true. | |
93 PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone); | |
94 ASSERT_NE(nullptr, op1); | |
95 EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&ppb1, 1, NULL)); | |
96 EXPECT_FALSE(op1->IsAction()); | |
97 | |
98 // This opcode always evaluates to false. | |
99 PolicyOpcode* op2 = opcode_maker.MakeOpAlwaysTrue(kPolNone); | |
100 ASSERT_NE(nullptr, op2); | |
101 EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL)); | |
102 | |
103 // Nulls not allowed on the params. | |
104 EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 0, NULL)); | |
105 EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 1, NULL)); | |
106 | |
107 // True and False opcodes do not 'require' a number of parameters | |
108 EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 0, NULL)); | |
109 EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL)); | |
110 | |
111 // Test Inverting the logic. Note that inversion is done outside | |
112 // any particular opcode evaluation so no need to repeat for all | |
113 // opcodes. | |
114 PolicyOpcode* op3 = opcode_maker.MakeOpAlwaysFalse(kPolNegateEval); | |
115 ASSERT_NE(nullptr, op3); | |
116 EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&ppb1, 1, NULL)); | |
117 PolicyOpcode* op4 = opcode_maker.MakeOpAlwaysTrue(kPolNegateEval); | |
118 ASSERT_NE(nullptr, op4); | |
119 EXPECT_EQ(EVAL_FALSE, op4->Evaluate(&ppb1, 1, NULL)); | |
120 | |
121 // Test that we clear the match context | |
122 PolicyOpcode* op5 = opcode_maker.MakeOpAlwaysTrue(kPolClearContext); | |
123 ASSERT_NE(nullptr, op5); | |
124 MatchContext context; | |
125 context.position = 1; | |
126 context.options = kPolUseOREval; | |
127 EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&ppb1, 1, &context)); | |
128 EXPECT_EQ(0u, context.position); | |
129 MatchContext context2; | |
130 EXPECT_EQ(context2.options, context.options); | |
131 } | |
132 | |
133 TEST(PolicyEngineTest, OpcodeMakerCase1) { | |
134 // Testing that the opcode maker does not overrun the | |
135 // supplied buffer. It should only be able to make 'count' opcodes. | |
136 void* dummy = NULL; | |
137 ParameterSet ppb1 = ParamPickerMake(dummy); | |
138 | |
139 char memory[kOpcodeMemory]; | |
140 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
141 size_t count = sizeof(memory) / sizeof(PolicyOpcode); | |
142 | |
143 for (size_t ix =0; ix != count; ++ix) { | |
144 PolicyOpcode* op = opcode_maker.MakeOpAlwaysFalse(kPolNone); | |
145 ASSERT_NE(nullptr, op); | |
146 EXPECT_EQ(EVAL_FALSE, op->Evaluate(&ppb1, 1, NULL)); | |
147 } | |
148 // There should be no room more another opcode: | |
149 PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone); | |
150 ASSERT_EQ(nullptr, op1); | |
151 } | |
152 | |
153 TEST(PolicyEngineTest, OpcodeMakerCase2) { | |
154 SetupNtdllImports(); | |
155 // Testing that the opcode maker does not overrun the | |
156 // supplied buffer. It should only be able to make 'count' opcodes. | |
157 // The difference with the previous test is that this opcodes allocate | |
158 // the string 'txt2' inside the same buffer. | |
159 const wchar_t* txt1 = L"1234"; | |
160 const wchar_t txt2[] = L"123"; | |
161 | |
162 ParameterSet ppb1 = ParamPickerMake(txt1); | |
163 MatchContext mc1; | |
164 | |
165 char memory[kOpcodeMemory]; | |
166 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
167 size_t count = sizeof(memory) / (sizeof(PolicyOpcode) + sizeof(txt2)); | |
168 | |
169 // Test that it does not overrun the buffer. | |
170 for (size_t ix =0; ix != count; ++ix) { | |
171 PolicyOpcode* op = opcode_maker.MakeOpWStringMatch(0, txt2, 0, | |
172 CASE_SENSITIVE, | |
173 kPolClearContext); | |
174 ASSERT_NE(nullptr, op); | |
175 EXPECT_EQ(EVAL_TRUE, op->Evaluate(&ppb1, 1, &mc1)); | |
176 } | |
177 | |
178 // There should be no room more another opcode: | |
179 PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0, | |
180 CASE_SENSITIVE, | |
181 kPolNone); | |
182 ASSERT_EQ(nullptr, op1); | |
183 } | |
184 | |
185 TEST(PolicyEngineTest, IntegerOpcodes) { | |
186 const wchar_t* txt = L"abcdef"; | |
187 uint32_t num1 = 42; | |
188 uint32_t num2 = 113377; | |
189 | |
190 ParameterSet pp_wrong1 = ParamPickerMake(txt); | |
191 ParameterSet pp_num1 = ParamPickerMake(num1); | |
192 ParameterSet pp_num2 = ParamPickerMake(num2); | |
193 | |
194 char memory[kOpcodeMemory]; | |
195 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
196 | |
197 // Test basic match for uint32s 42 == 42 and 42 != 113377. | |
198 PolicyOpcode* op_m42 = opcode_maker.MakeOpNumberMatch(0, 42UL, kPolNone); | |
199 ASSERT_NE(nullptr, op_m42); | |
200 EXPECT_EQ(EVAL_TRUE, op_m42->Evaluate(&pp_num1, 1, NULL)); | |
201 EXPECT_EQ(EVAL_FALSE, op_m42->Evaluate(&pp_num2, 1, NULL)); | |
202 EXPECT_EQ(EVAL_ERROR, op_m42->Evaluate(&pp_wrong1, 1, NULL)); | |
203 | |
204 // Test basic match for void pointers. | |
205 const void* vp = NULL; | |
206 ParameterSet pp_num3 = ParamPickerMake(vp); | |
207 PolicyOpcode* op_vp_null = opcode_maker.MakeOpVoidPtrMatch(0, NULL, | |
208 kPolNone); | |
209 ASSERT_NE(nullptr, op_vp_null); | |
210 EXPECT_EQ(EVAL_TRUE, op_vp_null->Evaluate(&pp_num3, 1, NULL)); | |
211 EXPECT_EQ(EVAL_FALSE, op_vp_null->Evaluate(&pp_num1, 1, NULL)); | |
212 EXPECT_EQ(EVAL_ERROR, op_vp_null->Evaluate(&pp_wrong1, 1, NULL)); | |
213 | |
214 // Basic range test [41 43] (inclusive). | |
215 PolicyOpcode* op_range1 = | |
216 opcode_maker.MakeOpNumberMatchRange(0, 41, 43, kPolNone); | |
217 ASSERT_NE(nullptr, op_range1); | |
218 EXPECT_EQ(EVAL_TRUE, op_range1->Evaluate(&pp_num1, 1, NULL)); | |
219 EXPECT_EQ(EVAL_FALSE, op_range1->Evaluate(&pp_num2, 1, NULL)); | |
220 EXPECT_EQ(EVAL_ERROR, op_range1->Evaluate(&pp_wrong1, 1, NULL)); | |
221 } | |
222 | |
223 TEST(PolicyEngineTest, LogicalOpcodes) { | |
224 char memory[kOpcodeMemory]; | |
225 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
226 | |
227 uint32_t num1 = 0x10100702; | |
228 ParameterSet pp_num1 = ParamPickerMake(num1); | |
229 | |
230 PolicyOpcode* op_and1 = | |
231 opcode_maker.MakeOpNumberAndMatch(0, 0x00100000, kPolNone); | |
232 ASSERT_NE(nullptr, op_and1); | |
233 EXPECT_EQ(EVAL_TRUE, op_and1->Evaluate(&pp_num1, 1, NULL)); | |
234 PolicyOpcode* op_and2 = | |
235 opcode_maker.MakeOpNumberAndMatch(0, 0x00000001, kPolNone); | |
236 ASSERT_NE(nullptr, op_and2); | |
237 EXPECT_EQ(EVAL_FALSE, op_and2->Evaluate(&pp_num1, 1, NULL)); | |
238 } | |
239 | |
240 TEST(PolicyEngineTest, WCharOpcodes1) { | |
241 SetupNtdllImports(); | |
242 | |
243 const wchar_t* txt1 = L"the quick fox jumps over the lazy dog"; | |
244 const wchar_t txt2[] = L"the quick"; | |
245 const wchar_t txt3[] = L" fox jumps"; | |
246 const wchar_t txt4[] = L"the lazy dog"; | |
247 const wchar_t txt5[] = L"jumps over"; | |
248 const wchar_t txt6[] = L"g"; | |
249 | |
250 ParameterSet pp_tc1 = ParamPickerMake(txt1); | |
251 char memory[kOpcodeMemory]; | |
252 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
253 | |
254 PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0, | |
255 CASE_SENSITIVE, | |
256 kPolNone); | |
257 ASSERT_NE(nullptr, op1); | |
258 | |
259 // Simplest substring match from pos 0. It should be a successful match | |
260 // and the match context should be updated. | |
261 MatchContext mc1; | |
262 EXPECT_EQ(EVAL_TRUE, op1->Evaluate(&pp_tc1, 1, &mc1)); | |
263 EXPECT_TRUE(_countof(txt2) == mc1.position + 1); | |
264 | |
265 // Matching again should fail and the context should be unmodified. | |
266 EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&pp_tc1, 1, &mc1)); | |
267 EXPECT_TRUE(_countof(txt2) == mc1.position + 1); | |
268 | |
269 // Using the same match context we should continue where we left | |
270 // in the previous successful match, | |
271 PolicyOpcode* op3 = opcode_maker.MakeOpWStringMatch(0, txt3, 0, | |
272 CASE_SENSITIVE, | |
273 kPolNone); | |
274 ASSERT_NE(nullptr, op3); | |
275 EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&pp_tc1, 1, &mc1)); | |
276 EXPECT_TRUE(_countof(txt3) + _countof(txt2) == mc1.position + 2); | |
277 | |
278 // We now keep on matching but now we skip 6 characters which means | |
279 // we skip the string ' over '. And we zero the match context. This is | |
280 // the primitive that we use to build '??'. | |
281 PolicyOpcode* op4 = opcode_maker.MakeOpWStringMatch(0, txt4, 6, | |
282 CASE_SENSITIVE, | |
283 kPolClearContext); | |
284 ASSERT_NE(nullptr, op4); | |
285 EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1)); | |
286 EXPECT_EQ(0u, mc1.position); | |
287 | |
288 // Test that we can properly match the last part of the string | |
289 PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(0, txt4, kSeekToEnd, | |
290 CASE_SENSITIVE, | |
291 kPolClearContext); | |
292 ASSERT_NE(nullptr, op4b); | |
293 EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1)); | |
294 EXPECT_EQ(0u, mc1.position); | |
295 | |
296 // Test matching 'jumps over' over the entire string. This is the | |
297 // primitive we build '*' from. | |
298 PolicyOpcode* op5 = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekForward, | |
299 CASE_SENSITIVE, kPolNone); | |
300 ASSERT_NE(nullptr, op5); | |
301 EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&pp_tc1, 1, &mc1)); | |
302 EXPECT_EQ(24u, mc1.position); | |
303 | |
304 // Test that we don't match because it is not at the end of the string | |
305 PolicyOpcode* op5b = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekToEnd, | |
306 CASE_SENSITIVE, | |
307 kPolNone); | |
308 ASSERT_NE(nullptr, op5b); | |
309 EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1)); | |
310 EXPECT_EQ(24u, mc1.position); | |
311 | |
312 // Test that we function if the string does not fit. In this case we | |
313 // try to match 'the lazy dog' against 'he lazy dog'. | |
314 PolicyOpcode* op6 = opcode_maker.MakeOpWStringMatch(0, txt4, 2, | |
315 CASE_SENSITIVE, kPolNone); | |
316 ASSERT_NE(nullptr, op6); | |
317 EXPECT_EQ(EVAL_FALSE, op6->Evaluate(&pp_tc1, 1, &mc1)); | |
318 | |
319 // Testing matching against 'g' which should be the last char. | |
320 MatchContext mc2; | |
321 PolicyOpcode* op7 = opcode_maker.MakeOpWStringMatch(0, txt6, kSeekForward, | |
322 CASE_SENSITIVE, kPolNone); | |
323 ASSERT_NE(nullptr, op7); | |
324 EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2)); | |
325 EXPECT_EQ(37u, mc2.position); | |
326 | |
327 // Trying to match again should fail since we are in the last char. | |
328 // This also covers a couple of boundary conditions. | |
329 EXPECT_EQ(EVAL_FALSE, op7->Evaluate(&pp_tc1, 1, &mc2)); | |
330 EXPECT_EQ(37u, mc2.position); | |
331 } | |
332 | |
333 TEST(PolicyEngineTest, WCharOpcodes2) { | |
334 SetupNtdllImports(); | |
335 | |
336 const wchar_t* path1 = L"c:\\documents and settings\\Microsoft\\BLAH.txt"; | |
337 const wchar_t txt1[] = L"Settings\\microsoft"; | |
338 ParameterSet pp_tc1 = ParamPickerMake(path1); | |
339 | |
340 char memory[kOpcodeMemory]; | |
341 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
342 MatchContext mc1; | |
343 | |
344 // Testing case-insensitive does not buy us much since it this option | |
345 // is just passed to the Microsoft API that we use normally, but just for | |
346 // coverage, here it is: | |
347 PolicyOpcode* op1s = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward, | |
348 CASE_SENSITIVE, kPolNone); | |
349 ASSERT_NE(nullptr, op1s); | |
350 PolicyOpcode* op1i = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward, | |
351 CASE_INSENSITIVE, | |
352 kPolNone); | |
353 ASSERT_NE(nullptr, op1i); | |
354 EXPECT_EQ(EVAL_FALSE, op1s->Evaluate(&pp_tc1, 1, &mc1)); | |
355 EXPECT_EQ(EVAL_TRUE, op1i->Evaluate(&pp_tc1, 1, &mc1)); | |
356 EXPECT_EQ(35u, mc1.position); | |
357 } | |
358 | |
359 TEST(PolicyEngineTest, ActionOpcodes) { | |
360 char memory[kOpcodeMemory]; | |
361 OpcodeFactory opcode_maker(memory, sizeof(memory)); | |
362 MatchContext mc1; | |
363 void* dummy = NULL; | |
364 ParameterSet ppb1 = ParamPickerMake(dummy); | |
365 | |
366 PolicyOpcode* op1 = opcode_maker.MakeOpAction(ASK_BROKER, kPolNone); | |
367 ASSERT_NE(nullptr, op1); | |
368 EXPECT_TRUE(op1->IsAction()); | |
369 EXPECT_EQ(ASK_BROKER, op1->Evaluate(&ppb1, 1, &mc1)); | |
370 } | |
371 | |
372 } // namespace sandbox | |
OLD | NEW |