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 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, 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)); 192 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, 197 kPolNone); 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)); 201 202 // Basic range test [41 43] (inclusive). 203 PolicyOpcode* op_range1 = opcode_maker.MakeOpUlongMatchRange(0, 41, 43, 204 kPolNone); 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)); 208 } 209 210 TEST(PolicyEngineTest, LogicalOpcodes) { 211 char memory[128]; 212 OpcodeFactory opcode_maker(memory, sizeof(memory)); 213 214 unsigned long num1 = 0x10100702; 215 ParameterSet pp_num1 = ParamPickerMake(num1); 216 217 PolicyOpcode* op_and1 = opcode_maker.MakeOpUlongAndMatch(0, 0x00100000, 218 kPolNone); 219 EXPECT_EQ(EVAL_TRUE, op_and1->Evaluate(&pp_num1, 1, NULL)); 220 PolicyOpcode* op_and2 = opcode_maker.MakeOpUlongAndMatch(0, 0x00000001, 221 kPolNone); 222 EXPECT_EQ(EVAL_FALSE, op_and2->Evaluate(&pp_num1, 1, NULL)); 223 } 224 225 TEST(PolicyEngineTest, WCharOpcodes1) { 226 SetupNtdllImports(); 227 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"; 234 235 ParameterSet pp_tc1 = ParamPickerMake(txt1); 236 char memory[512]; 237 OpcodeFactory opcode_maker(memory, sizeof(memory)); 238 239 PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0, 240 CASE_SENSITIVE, 241 kPolNone); 242 243 // Simplest substring match from pos 0. It should be a successful match 244 // and the match context should be updated. 245 MatchContext mc1; 246 EXPECT_EQ(EVAL_TRUE, op1->Evaluate(&pp_tc1, 1, &mc1)); 247 EXPECT_TRUE(_countof(txt2) == mc1.position + 1); 248 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); 252 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, 256 CASE_SENSITIVE, 257 kPolNone); 258 EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&pp_tc1, 1, &mc1)); 259 EXPECT_TRUE(_countof(txt3) + _countof(txt2) == mc1.position + 2); 260 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, 265 CASE_SENSITIVE, 266 kPolClearContext); 267 EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1)); 268 EXPECT_EQ(0, mc1.position); 269 270 // Test that we can properly match the last part of the string 271 PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(0, txt4, kSeekToEnd, 272 CASE_SENSITIVE, 273 kPolClearContext); 274 EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1)); 275 EXPECT_EQ(0, mc1.position); 276 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); 283 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, 286 CASE_SENSITIVE, 287 kPolNone); 288 EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1)); 289 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); 295 296 // Testing matching against 'g' which should be the last char. 297 MatchContext mc2; 298 PolicyOpcode* op7 = opcode_maker.MakeOpWStringMatch(0, txt6, kSeekForward, 299 CASE_SENSITIVE, kPolNone); 300 EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2)); 301 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)); 305 } 306 307 TEST(PolicyEngineTest, WCharOpcodes2) { 308 SetupNtdllImports(); 309 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); 313 314 char memory[256]; 315 OpcodeFactory opcode_maker(memory, sizeof(memory)); 316 MatchContext mc1; 317 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, 324 CASE_INSENSITIVE, 325 kPolNone); 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); 329 } 330 331 TEST(PolicyEngineTest, ActionOpcodes) { 332 char memory[256]; 333 OpcodeFactory opcode_maker(memory, sizeof(memory)); 334 MatchContext mc1; 335 void* dummy = NULL; 336 ParameterSet ppb1 = ParamPickerMake(dummy); 337 338 PolicyOpcode* op1 = opcode_maker.MakeOpAction(ASK_BROKER, kPolNone); 339 EXPECT_TRUE(op1->IsAction()); 340 EXPECT_EQ(ASK_BROKER, op1->Evaluate(&ppb1, 1, &mc1)); 341 } 342 343 } // namespace sandbox 344