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.
5 #include "sandbox/win/src/sandbox_types.h"
6 #include "sandbox/win/src/sandbox_nt_types.h"
7 #include "sandbox/win/src/policy_engine_params.h"
8 #include "sandbox/win/src/policy_engine_opcodes.h"
9 #include "testing/gtest/include/gtest/gtest.h"
12 #define INIT_GLOBAL_RTL(member) \
13 g_nt.member = reinterpret_cast<member##Function>( \
14 ::GetProcAddress(ntdll, #member)); \
15 if (NULL == g_nt.member) \
20 SANDBOX_INTERCEPT NtExports g_nt
;
22 bool SetupNtdllImports() {
23 HMODULE ntdll
= ::GetModuleHandle(kNtdllName
);
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
);
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
);
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
));
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
);
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
));
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
));
81 TEST(PolicyEngineTest
, TrueFalseOpcodes
) {
83 ParameterSet ppb1
= ParamPickerMake(dummy
);
85 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
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());
92 // This opcode always evaluates to false.
93 PolicyOpcode
* op2
= opcode_maker
.MakeOpAlwaysTrue(kPolNone
);
94 EXPECT_EQ(EVAL_TRUE
, op2
->Evaluate(&ppb1
, 1, NULL
));
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
));
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
));
104 // Test Inverting the logic. Note that inversion is done outside
105 // any particular opcode evaluation so no need to repeat for all
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
));
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
);
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.
127 ParameterSet ppb1
= ParamPickerMake(dummy
);
130 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
131 size_t count
= sizeof(memory
) / sizeof(PolicyOpcode
);
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
));
138 // There should be no room more another opcode:
139 PolicyOpcode
* op1
= opcode_maker
.MakeOpAlwaysFalse(kPolNone
);
140 ASSERT_TRUE(NULL
== op1
);
143 TEST(PolicyEngineTest
, OpcodeMakerCase2
) {
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";
152 ParameterSet ppb1
= ParamPickerMake(txt1
);
156 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
157 size_t count
= sizeof(memory
) / (sizeof(PolicyOpcode
) + sizeof(txt2
));
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,
164 ASSERT_TRUE(NULL
!= op
);
165 EXPECT_EQ(EVAL_TRUE
, op
->Evaluate(&ppb1
, 1, &mc1
));
168 // There should be no room more another opcode:
169 PolicyOpcode
* op1
= opcode_maker
.MakeOpWStringMatch(0, txt2
, 0,
172 ASSERT_TRUE(NULL
== op1
);
175 TEST(PolicyEngineTest
, IntegerOpcodes
) {
176 const wchar_t* txt
= L
"abcdef";
177 unsigned long num1
= 42;
178 unsigned long num2
= 113377;
180 ParameterSet pp_wrong1
= ParamPickerMake(txt
);
181 ParameterSet pp_num1
= ParamPickerMake(num1
);
182 ParameterSet pp_num2
= ParamPickerMake(num2
);
185 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
187 // Test basic match for unsigned longs 42 == 42 and 42 != 113377.
188 PolicyOpcode
* op_m42
= opcode_maker
.MakeOpNumberMatch(0, 42UL, kPolNone
);
189 EXPECT_EQ(EVAL_TRUE
, op_m42
->Evaluate(&pp_num1
, 1, NULL
));
190 EXPECT_EQ(EVAL_FALSE
, op_m42
->Evaluate(&pp_num2
, 1, NULL
));
191 EXPECT_EQ(EVAL_ERROR
, op_m42
->Evaluate(&pp_wrong1
, 1, NULL
));
193 // Test basic match for void pointers.
194 const void* vp
= NULL
;
195 ParameterSet pp_num3
= ParamPickerMake(vp
);
196 PolicyOpcode
* op_vp_null
= opcode_maker
.MakeOpVoidPtrMatch(0, NULL
,
198 EXPECT_EQ(EVAL_TRUE
, op_vp_null
->Evaluate(&pp_num3
, 1, NULL
));
199 EXPECT_EQ(EVAL_FALSE
, op_vp_null
->Evaluate(&pp_num1
, 1, NULL
));
200 EXPECT_EQ(EVAL_ERROR
, op_vp_null
->Evaluate(&pp_wrong1
, 1, NULL
));
202 // Basic range test [41 43] (inclusive).
203 PolicyOpcode
* op_range1
= opcode_maker
.MakeOpUlongMatchRange(0, 41, 43,
205 EXPECT_EQ(EVAL_TRUE
, op_range1
->Evaluate(&pp_num1
, 1, NULL
));
206 EXPECT_EQ(EVAL_FALSE
, op_range1
->Evaluate(&pp_num2
, 1, NULL
));
207 EXPECT_EQ(EVAL_ERROR
, op_range1
->Evaluate(&pp_wrong1
, 1, NULL
));
210 TEST(PolicyEngineTest
, LogicalOpcodes
) {
212 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
214 unsigned long num1
= 0x10100702;
215 ParameterSet pp_num1
= ParamPickerMake(num1
);
217 PolicyOpcode
* op_and1
= opcode_maker
.MakeOpUlongAndMatch(0, 0x00100000,
219 EXPECT_EQ(EVAL_TRUE
, op_and1
->Evaluate(&pp_num1
, 1, NULL
));
220 PolicyOpcode
* op_and2
= opcode_maker
.MakeOpUlongAndMatch(0, 0x00000001,
222 EXPECT_EQ(EVAL_FALSE
, op_and2
->Evaluate(&pp_num1
, 1, NULL
));
225 TEST(PolicyEngineTest
, WCharOpcodes1
) {
228 const wchar_t* txt1
= L
"the quick fox jumps over the lazy dog";
229 const wchar_t txt2
[] = L
"the quick";
230 const wchar_t txt3
[] = L
" fox jumps";
231 const wchar_t txt4
[] = L
"the lazy dog";
232 const wchar_t txt5
[] = L
"jumps over";
233 const wchar_t txt6
[] = L
"g";
235 ParameterSet pp_tc1
= ParamPickerMake(txt1
);
237 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
239 PolicyOpcode
* op1
= opcode_maker
.MakeOpWStringMatch(0, txt2
, 0,
243 // Simplest substring match from pos 0. It should be a successful match
244 // and the match context should be updated.
246 EXPECT_EQ(EVAL_TRUE
, op1
->Evaluate(&pp_tc1
, 1, &mc1
));
247 EXPECT_TRUE(_countof(txt2
) == mc1
.position
+ 1);
249 // Matching again should fail and the context should be unmodified.
250 EXPECT_EQ(EVAL_FALSE
, op1
->Evaluate(&pp_tc1
, 1, &mc1
));
251 EXPECT_TRUE(_countof(txt2
) == mc1
.position
+ 1);
253 // Using the same match context we should continue where we left
254 // in the previous successful match,
255 PolicyOpcode
* op3
= opcode_maker
.MakeOpWStringMatch(0, txt3
, 0,
258 EXPECT_EQ(EVAL_TRUE
, op3
->Evaluate(&pp_tc1
, 1, &mc1
));
259 EXPECT_TRUE(_countof(txt3
) + _countof(txt2
) == mc1
.position
+ 2);
261 // We now keep on matching but now we skip 6 characters which means
262 // we skip the string ' over '. And we zero the match context. This is
263 // the primitive that we use to build '??'.
264 PolicyOpcode
* op4
= opcode_maker
.MakeOpWStringMatch(0, txt4
, 6,
267 EXPECT_EQ(EVAL_TRUE
, op4
->Evaluate(&pp_tc1
, 1, &mc1
));
268 EXPECT_EQ(0, mc1
.position
);
270 // Test that we can properly match the last part of the string
271 PolicyOpcode
* op4b
= opcode_maker
.MakeOpWStringMatch(0, txt4
, kSeekToEnd
,
274 EXPECT_EQ(EVAL_TRUE
, op4b
->Evaluate(&pp_tc1
, 1, &mc1
));
275 EXPECT_EQ(0, mc1
.position
);
277 // Test matching 'jumps over' over the entire string. This is the
278 // primitive we build '*' from.
279 PolicyOpcode
* op5
= opcode_maker
.MakeOpWStringMatch(0, txt5
, kSeekForward
,
280 CASE_SENSITIVE
, kPolNone
);
281 EXPECT_EQ(EVAL_TRUE
, op5
->Evaluate(&pp_tc1
, 1, &mc1
));
282 EXPECT_EQ(24, mc1
.position
);
284 // Test that we don't match because it is not at the end of the string
285 PolicyOpcode
* op5b
= opcode_maker
.MakeOpWStringMatch(0, txt5
, kSeekToEnd
,
288 EXPECT_EQ(EVAL_FALSE
, op5b
->Evaluate(&pp_tc1
, 1, &mc1
));
290 // Test that we function if the string does not fit. In this case we
291 // try to match 'the lazy dog' against 'he lazy dog'.
292 PolicyOpcode
* op6
= opcode_maker
.MakeOpWStringMatch(0, txt4
, 2,
293 CASE_SENSITIVE
, kPolNone
);
294 EXPECT_EQ(24, mc1
.position
);
296 // Testing matching against 'g' which should be the last char.
298 PolicyOpcode
* op7
= opcode_maker
.MakeOpWStringMatch(0, txt6
, kSeekForward
,
299 CASE_SENSITIVE
, kPolNone
);
300 EXPECT_EQ(EVAL_TRUE
, op7
->Evaluate(&pp_tc1
, 1, &mc2
));
302 // Trying to match again should fail since we are in the last char.
303 // This also covers a couple of boundary conditions.
304 EXPECT_EQ(EVAL_FALSE
, op7
->Evaluate(&pp_tc1
, 1, &mc2
));
307 TEST(PolicyEngineTest
, WCharOpcodes2
) {
310 const wchar_t* path1
= L
"c:\\documents and settings\\Microsoft\\BLAH.txt";
311 const wchar_t txt1
[] = L
"Settings\\microsoft";
312 ParameterSet pp_tc1
= ParamPickerMake(path1
);
315 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
318 // Testing case-insensitive does not buy us much since it this option
319 // is just passed to the Microsoft API that we use normally, but just for
320 // coverage, here it is:
321 PolicyOpcode
* op1s
= opcode_maker
.MakeOpWStringMatch(0, txt1
, kSeekForward
,
322 CASE_SENSITIVE
, kPolNone
);
323 PolicyOpcode
* op1i
= opcode_maker
.MakeOpWStringMatch(0, txt1
, kSeekForward
,
326 EXPECT_EQ(EVAL_FALSE
, op1s
->Evaluate(&pp_tc1
, 1, &mc1
));
327 EXPECT_EQ(EVAL_TRUE
, op1i
->Evaluate(&pp_tc1
, 1, &mc1
));
328 EXPECT_EQ(35, mc1
.position
);
331 TEST(PolicyEngineTest
, ActionOpcodes
) {
333 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
336 ParameterSet ppb1
= ParamPickerMake(dummy
);
338 PolicyOpcode
* op1
= opcode_maker
.MakeOpAction(ASK_BROKER
, kPolNone
);
339 EXPECT_TRUE(op1
->IsAction());
340 EXPECT_EQ(ASK_BROKER
, op1
->Evaluate(&ppb1
, 1, &mc1
));
343 } // namespace sandbox