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