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