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/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"
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
18namespace sandbox {
19
20SANDBOX_INTERCEPT NtExports g_nt;
21
22bool 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
38TEST(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
69TEST(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
81TEST(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
123TEST(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
143TEST(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
175TEST(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
211TEST(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
226TEST(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
308TEST(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
332TEST(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
345