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