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, unsigned long(42),
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
));
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
,
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
));
203 // Basic range test [41 43] (inclusive).
204 PolicyOpcode
* op_range1
= opcode_maker
.MakeOpUlongMatchRange(0, 41, 43,
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
));
211 TEST(PolicyEngineTest
, LogicalOpcodes
) {
213 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
215 unsigned long num1
= 0x10100702;
216 ParameterSet pp_num1
= ParamPickerMake(num1
);
218 PolicyOpcode
* op_and1
= opcode_maker
.MakeOpUlongAndMatch(0, 0x00100000,
220 EXPECT_EQ(EVAL_TRUE
, op_and1
->Evaluate(&pp_num1
, 1, NULL
));
221 PolicyOpcode
* op_and2
= opcode_maker
.MakeOpUlongAndMatch(0, 0x00000001,
223 EXPECT_EQ(EVAL_FALSE
, op_and2
->Evaluate(&pp_num1
, 1, NULL
));
226 TEST(PolicyEngineTest
, WCharOpcodes1
) {
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";
236 ParameterSet pp_tc1
= ParamPickerMake(txt1
);
238 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
240 PolicyOpcode
* op1
= opcode_maker
.MakeOpWStringMatch(0, txt2
, 0,
244 // Simplest substring match from pos 0. It should be a successful match
245 // and the match context should be updated.
247 EXPECT_EQ(EVAL_TRUE
, op1
->Evaluate(&pp_tc1
, 1, &mc1
));
248 EXPECT_TRUE(_countof(txt2
) == mc1
.position
+ 1);
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);
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,
259 EXPECT_EQ(EVAL_TRUE
, op3
->Evaluate(&pp_tc1
, 1, &mc1
));
260 EXPECT_TRUE(_countof(txt3
) + _countof(txt2
) == mc1
.position
+ 2);
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,
268 EXPECT_EQ(EVAL_TRUE
, op4
->Evaluate(&pp_tc1
, 1, &mc1
));
269 EXPECT_EQ(0, mc1
.position
);
271 // Test that we can properly match the last part of the string
272 PolicyOpcode
* op4b
= opcode_maker
.MakeOpWStringMatch(0, txt4
, kSeekToEnd
,
275 EXPECT_EQ(EVAL_TRUE
, op4b
->Evaluate(&pp_tc1
, 1, &mc1
));
276 EXPECT_EQ(0, mc1
.position
);
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
);
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
,
289 EXPECT_EQ(EVAL_FALSE
, op5b
->Evaluate(&pp_tc1
, 1, &mc1
));
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
);
297 // Testing matching against 'g' which should be the last char.
299 PolicyOpcode
* op7
= opcode_maker
.MakeOpWStringMatch(0, txt6
, kSeekForward
,
300 CASE_SENSITIVE
, kPolNone
);
301 EXPECT_EQ(EVAL_TRUE
, op7
->Evaluate(&pp_tc1
, 1, &mc2
));
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
));
308 TEST(PolicyEngineTest
, WCharOpcodes2
) {
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
);
316 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
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
,
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
);
332 TEST(PolicyEngineTest
, ActionOpcodes
) {
334 OpcodeFactory
opcode_maker(memory
, sizeof(memory
));
337 ParameterSet ppb1
= ParamPickerMake(dummy
);
339 PolicyOpcode
* op1
= opcode_maker
.MakeOpAction(ASK_BROKER
, kPolNone
);
340 EXPECT_TRUE(op1
->IsAction());
341 EXPECT_EQ(ASK_BROKER
, op1
->Evaluate(&ppb1
, 1, &mc1
));
344 } // namespace sandbox