1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/policy_opcodes_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,344 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/sandbox_types.h" 1.9 +#include "sandbox/win/src/sandbox_nt_types.h" 1.10 +#include "sandbox/win/src/policy_engine_params.h" 1.11 +#include "sandbox/win/src/policy_engine_opcodes.h" 1.12 +#include "testing/gtest/include/gtest/gtest.h" 1.13 + 1.14 + 1.15 +#define INIT_GLOBAL_RTL(member) \ 1.16 + g_nt.##member = reinterpret_cast<##member##Function>( \ 1.17 + ::GetProcAddress(ntdll, #member)); \ 1.18 + if (NULL == g_nt.##member) \ 1.19 + return false 1.20 + 1.21 +namespace sandbox { 1.22 + 1.23 +SANDBOX_INTERCEPT NtExports g_nt; 1.24 + 1.25 +bool SetupNtdllImports() { 1.26 + HMODULE ntdll = ::GetModuleHandle(kNtdllName); 1.27 + 1.28 + INIT_GLOBAL_RTL(RtlAllocateHeap); 1.29 + INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString); 1.30 + INIT_GLOBAL_RTL(RtlCompareUnicodeString); 1.31 + INIT_GLOBAL_RTL(RtlCreateHeap); 1.32 + INIT_GLOBAL_RTL(RtlDestroyHeap); 1.33 + INIT_GLOBAL_RTL(RtlFreeHeap); 1.34 + INIT_GLOBAL_RTL(_strnicmp); 1.35 + INIT_GLOBAL_RTL(strlen); 1.36 + INIT_GLOBAL_RTL(wcslen); 1.37 + 1.38 + return true; 1.39 +} 1.40 + 1.41 +TEST(PolicyEngineTest, ParameterSetTest) { 1.42 + void* pv1 = reinterpret_cast<void*>(0x477EAA5); 1.43 + const void* pv2 = reinterpret_cast<void*>(0x987654); 1.44 + ParameterSet pset1 = ParamPickerMake(pv1); 1.45 + ParameterSet pset2 = ParamPickerMake(pv2); 1.46 + 1.47 + // Test that we can store and retrieve a void pointer: 1.48 + const void* result1 =0; 1.49 + unsigned long result2 = 0; 1.50 + EXPECT_TRUE(pset1.Get(&result1)); 1.51 + EXPECT_TRUE(pv1 == result1); 1.52 + EXPECT_FALSE(pset1.Get(&result2)); 1.53 + EXPECT_TRUE(pset2.Get(&result1)); 1.54 + EXPECT_TRUE(pv2 == result1); 1.55 + EXPECT_FALSE(pset2.Get(&result2)); 1.56 + 1.57 + // Test that we can store and retrieve a ulong: 1.58 + unsigned long number = 12747; 1.59 + ParameterSet pset3 = ParamPickerMake(number); 1.60 + EXPECT_FALSE(pset3.Get(&result1)); 1.61 + EXPECT_TRUE(pset3.Get(&result2)); 1.62 + EXPECT_EQ(number, result2); 1.63 + 1.64 + // Test that we can store and retrieve a string: 1.65 + const wchar_t* txt = L"S231L"; 1.66 + ParameterSet pset4 = ParamPickerMake(txt); 1.67 + const wchar_t* result3 = NULL; 1.68 + EXPECT_TRUE(pset4.Get(&result3)); 1.69 + EXPECT_EQ(0, wcscmp(txt, result3)); 1.70 +} 1.71 + 1.72 +TEST(PolicyEngineTest, OpcodeConstraints) { 1.73 + // Test that PolicyOpcode has no virtual functions 1.74 + // because these objects are copied over to other processes 1.75 + // so they cannot have vtables. 1.76 + EXPECT_FALSE(__is_polymorphic(PolicyOpcode)); 1.77 + // Keep developers from adding smarts to the opcodes which should 1.78 + // be pretty much a bag of bytes with a OO interface. 1.79 + EXPECT_TRUE(__has_trivial_destructor(PolicyOpcode)); 1.80 + EXPECT_TRUE(__has_trivial_constructor(PolicyOpcode)); 1.81 + EXPECT_TRUE(__has_trivial_copy(PolicyOpcode)); 1.82 +} 1.83 + 1.84 +TEST(PolicyEngineTest, TrueFalseOpcodes) { 1.85 + void* dummy = NULL; 1.86 + ParameterSet ppb1 = ParamPickerMake(dummy); 1.87 + char memory[1024]; 1.88 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.89 + 1.90 + // This opcode always evaluates to true. 1.91 + PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone); 1.92 + EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&ppb1, 1, NULL)); 1.93 + EXPECT_FALSE(op1->IsAction()); 1.94 + 1.95 + // This opcode always evaluates to false. 1.96 + PolicyOpcode* op2 = opcode_maker.MakeOpAlwaysTrue(kPolNone); 1.97 + EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL)); 1.98 + 1.99 + // Nulls not allowed on the params. 1.100 + EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 0, NULL)); 1.101 + EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 1, NULL)); 1.102 + 1.103 + // True and False opcodes do not 'require' a number of parameters 1.104 + EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 0, NULL)); 1.105 + EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL)); 1.106 + 1.107 + // Test Inverting the logic. Note that inversion is done outside 1.108 + // any particular opcode evaluation so no need to repeat for all 1.109 + // opcodes. 1.110 + PolicyOpcode* op3 = opcode_maker.MakeOpAlwaysFalse(kPolNegateEval); 1.111 + EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&ppb1, 1, NULL)); 1.112 + PolicyOpcode* op4 = opcode_maker.MakeOpAlwaysTrue(kPolNegateEval); 1.113 + EXPECT_EQ(EVAL_FALSE, op4->Evaluate(&ppb1, 1, NULL)); 1.114 + 1.115 + // Test that we clear the match context 1.116 + PolicyOpcode* op5 = opcode_maker.MakeOpAlwaysTrue(kPolClearContext); 1.117 + MatchContext context; 1.118 + context.position = 1; 1.119 + context.options = kPolUseOREval; 1.120 + EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&ppb1, 1, &context)); 1.121 + EXPECT_EQ(0, context.position); 1.122 + MatchContext context2; 1.123 + EXPECT_EQ(context2.options, context.options); 1.124 +} 1.125 + 1.126 +TEST(PolicyEngineTest, OpcodeMakerCase1) { 1.127 + // Testing that the opcode maker does not overrun the 1.128 + // supplied buffer. It should only be able to make 'count' opcodes. 1.129 + void* dummy = NULL; 1.130 + ParameterSet ppb1 = ParamPickerMake(dummy); 1.131 + 1.132 + char memory[256]; 1.133 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.134 + size_t count = sizeof(memory) / sizeof(PolicyOpcode); 1.135 + 1.136 + for (size_t ix =0; ix != count; ++ix) { 1.137 + PolicyOpcode* op = opcode_maker.MakeOpAlwaysFalse(kPolNone); 1.138 + ASSERT_TRUE(NULL != op); 1.139 + EXPECT_EQ(EVAL_FALSE, op->Evaluate(&ppb1, 1, NULL)); 1.140 + } 1.141 + // There should be no room more another opcode: 1.142 + PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone); 1.143 + ASSERT_TRUE(NULL == op1); 1.144 +} 1.145 + 1.146 +TEST(PolicyEngineTest, OpcodeMakerCase2) { 1.147 + SetupNtdllImports(); 1.148 + // Testing that the opcode maker does not overrun the 1.149 + // supplied buffer. It should only be able to make 'count' opcodes. 1.150 + // The difference with the previous test is that this opcodes allocate 1.151 + // the string 'txt2' inside the same buffer. 1.152 + const wchar_t* txt1 = L"1234"; 1.153 + const wchar_t txt2[] = L"123"; 1.154 + 1.155 + ParameterSet ppb1 = ParamPickerMake(txt1); 1.156 + MatchContext mc1; 1.157 + 1.158 + char memory[256]; 1.159 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.160 + size_t count = sizeof(memory) / (sizeof(PolicyOpcode) + sizeof(txt2)); 1.161 + 1.162 + // Test that it does not overrun the buffer. 1.163 + for (size_t ix =0; ix != count; ++ix) { 1.164 + PolicyOpcode* op = opcode_maker.MakeOpWStringMatch(0, txt2, 0, 1.165 + CASE_SENSITIVE, 1.166 + kPolClearContext); 1.167 + ASSERT_TRUE(NULL != op); 1.168 + EXPECT_EQ(EVAL_TRUE, op->Evaluate(&ppb1, 1, &mc1)); 1.169 + } 1.170 + 1.171 + // There should be no room more another opcode: 1.172 + PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0, 1.173 + CASE_SENSITIVE, 1.174 + kPolNone); 1.175 + ASSERT_TRUE(NULL == op1); 1.176 +} 1.177 + 1.178 +TEST(PolicyEngineTest, IntegerOpcodes) { 1.179 + const wchar_t* txt = L"abcdef"; 1.180 + unsigned long num1 = 42; 1.181 + unsigned long num2 = 113377; 1.182 + 1.183 + ParameterSet pp_wrong1 = ParamPickerMake(txt); 1.184 + ParameterSet pp_num1 = ParamPickerMake(num1); 1.185 + ParameterSet pp_num2 = ParamPickerMake(num2); 1.186 + 1.187 + char memory[128]; 1.188 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.189 + 1.190 + // Test basic match for unsigned longs 42 == 42 and 42 != 113377. 1.191 + PolicyOpcode* op_m42 = opcode_maker.MakeOpNumberMatch(0, unsigned long(42), 1.192 + kPolNone); 1.193 + EXPECT_EQ(EVAL_TRUE, op_m42->Evaluate(&pp_num1, 1, NULL)); 1.194 + EXPECT_EQ(EVAL_FALSE, op_m42->Evaluate(&pp_num2, 1, NULL)); 1.195 + EXPECT_EQ(EVAL_ERROR, op_m42->Evaluate(&pp_wrong1, 1, NULL)); 1.196 + 1.197 + // Test basic match for void pointers. 1.198 + const void* vp = NULL; 1.199 + ParameterSet pp_num3 = ParamPickerMake(vp); 1.200 + PolicyOpcode* op_vp_null = opcode_maker.MakeOpVoidPtrMatch(0, NULL, 1.201 + kPolNone); 1.202 + EXPECT_EQ(EVAL_TRUE, op_vp_null->Evaluate(&pp_num3, 1, NULL)); 1.203 + EXPECT_EQ(EVAL_FALSE, op_vp_null->Evaluate(&pp_num1, 1, NULL)); 1.204 + EXPECT_EQ(EVAL_ERROR, op_vp_null->Evaluate(&pp_wrong1, 1, NULL)); 1.205 + 1.206 + // Basic range test [41 43] (inclusive). 1.207 + PolicyOpcode* op_range1 = opcode_maker.MakeOpUlongMatchRange(0, 41, 43, 1.208 + kPolNone); 1.209 + EXPECT_EQ(EVAL_TRUE, op_range1->Evaluate(&pp_num1, 1, NULL)); 1.210 + EXPECT_EQ(EVAL_FALSE, op_range1->Evaluate(&pp_num2, 1, NULL)); 1.211 + EXPECT_EQ(EVAL_ERROR, op_range1->Evaluate(&pp_wrong1, 1, NULL)); 1.212 +} 1.213 + 1.214 +TEST(PolicyEngineTest, LogicalOpcodes) { 1.215 + char memory[128]; 1.216 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.217 + 1.218 + unsigned long num1 = 0x10100702; 1.219 + ParameterSet pp_num1 = ParamPickerMake(num1); 1.220 + 1.221 + PolicyOpcode* op_and1 = opcode_maker.MakeOpUlongAndMatch(0, 0x00100000, 1.222 + kPolNone); 1.223 + EXPECT_EQ(EVAL_TRUE, op_and1->Evaluate(&pp_num1, 1, NULL)); 1.224 + PolicyOpcode* op_and2 = opcode_maker.MakeOpUlongAndMatch(0, 0x00000001, 1.225 + kPolNone); 1.226 + EXPECT_EQ(EVAL_FALSE, op_and2->Evaluate(&pp_num1, 1, NULL)); 1.227 +} 1.228 + 1.229 +TEST(PolicyEngineTest, WCharOpcodes1) { 1.230 + SetupNtdllImports(); 1.231 + 1.232 + const wchar_t* txt1 = L"the quick fox jumps over the lazy dog"; 1.233 + const wchar_t txt2[] = L"the quick"; 1.234 + const wchar_t txt3[] = L" fox jumps"; 1.235 + const wchar_t txt4[] = L"the lazy dog"; 1.236 + const wchar_t txt5[] = L"jumps over"; 1.237 + const wchar_t txt6[] = L"g"; 1.238 + 1.239 + ParameterSet pp_tc1 = ParamPickerMake(txt1); 1.240 + char memory[512]; 1.241 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.242 + 1.243 + PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0, 1.244 + CASE_SENSITIVE, 1.245 + kPolNone); 1.246 + 1.247 + // Simplest substring match from pos 0. It should be a successful match 1.248 + // and the match context should be updated. 1.249 + MatchContext mc1; 1.250 + EXPECT_EQ(EVAL_TRUE, op1->Evaluate(&pp_tc1, 1, &mc1)); 1.251 + EXPECT_TRUE(_countof(txt2) == mc1.position + 1); 1.252 + 1.253 + // Matching again should fail and the context should be unmodified. 1.254 + EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&pp_tc1, 1, &mc1)); 1.255 + EXPECT_TRUE(_countof(txt2) == mc1.position + 1); 1.256 + 1.257 + // Using the same match context we should continue where we left 1.258 + // in the previous successful match, 1.259 + PolicyOpcode* op3 = opcode_maker.MakeOpWStringMatch(0, txt3, 0, 1.260 + CASE_SENSITIVE, 1.261 + kPolNone); 1.262 + EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&pp_tc1, 1, &mc1)); 1.263 + EXPECT_TRUE(_countof(txt3) + _countof(txt2) == mc1.position + 2); 1.264 + 1.265 + // We now keep on matching but now we skip 6 characters which means 1.266 + // we skip the string ' over '. And we zero the match context. This is 1.267 + // the primitive that we use to build '??'. 1.268 + PolicyOpcode* op4 = opcode_maker.MakeOpWStringMatch(0, txt4, 6, 1.269 + CASE_SENSITIVE, 1.270 + kPolClearContext); 1.271 + EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1)); 1.272 + EXPECT_EQ(0, mc1.position); 1.273 + 1.274 + // Test that we can properly match the last part of the string 1.275 + PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(0, txt4, kSeekToEnd, 1.276 + CASE_SENSITIVE, 1.277 + kPolClearContext); 1.278 + EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1)); 1.279 + EXPECT_EQ(0, mc1.position); 1.280 + 1.281 + // Test matching 'jumps over' over the entire string. This is the 1.282 + // primitive we build '*' from. 1.283 + PolicyOpcode* op5 = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekForward, 1.284 + CASE_SENSITIVE, kPolNone); 1.285 + EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&pp_tc1, 1, &mc1)); 1.286 + EXPECT_EQ(24, mc1.position); 1.287 + 1.288 + // Test that we don't match because it is not at the end of the string 1.289 + PolicyOpcode* op5b = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekToEnd, 1.290 + CASE_SENSITIVE, 1.291 + kPolNone); 1.292 + EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1)); 1.293 + 1.294 + // Test that we function if the string does not fit. In this case we 1.295 + // try to match 'the lazy dog' against 'he lazy dog'. 1.296 + PolicyOpcode* op6 = opcode_maker.MakeOpWStringMatch(0, txt4, 2, 1.297 + CASE_SENSITIVE, kPolNone); 1.298 + EXPECT_EQ(24, mc1.position); 1.299 + 1.300 + // Testing matching against 'g' which should be the last char. 1.301 + MatchContext mc2; 1.302 + PolicyOpcode* op7 = opcode_maker.MakeOpWStringMatch(0, txt6, kSeekForward, 1.303 + CASE_SENSITIVE, kPolNone); 1.304 + EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2)); 1.305 + 1.306 + // Trying to match again should fail since we are in the last char. 1.307 + // This also covers a couple of boundary conditions. 1.308 + EXPECT_EQ(EVAL_FALSE, op7->Evaluate(&pp_tc1, 1, &mc2)); 1.309 +} 1.310 + 1.311 +TEST(PolicyEngineTest, WCharOpcodes2) { 1.312 + SetupNtdllImports(); 1.313 + 1.314 + const wchar_t* path1 = L"c:\\documents and settings\\Microsoft\\BLAH.txt"; 1.315 + const wchar_t txt1[] = L"Settings\\microsoft"; 1.316 + ParameterSet pp_tc1 = ParamPickerMake(path1); 1.317 + 1.318 + char memory[256]; 1.319 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.320 + MatchContext mc1; 1.321 + 1.322 + // Testing case-insensitive does not buy us much since it this option 1.323 + // is just passed to the Microsoft API that we use normally, but just for 1.324 + // coverage, here it is: 1.325 + PolicyOpcode* op1s = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward, 1.326 + CASE_SENSITIVE, kPolNone); 1.327 + PolicyOpcode* op1i = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward, 1.328 + CASE_INSENSITIVE, 1.329 + kPolNone); 1.330 + EXPECT_EQ(EVAL_FALSE, op1s->Evaluate(&pp_tc1, 1, &mc1)); 1.331 + EXPECT_EQ(EVAL_TRUE, op1i->Evaluate(&pp_tc1, 1, &mc1)); 1.332 + EXPECT_EQ(35, mc1.position); 1.333 +} 1.334 + 1.335 +TEST(PolicyEngineTest, ActionOpcodes) { 1.336 + char memory[256]; 1.337 + OpcodeFactory opcode_maker(memory, sizeof(memory)); 1.338 + MatchContext mc1; 1.339 + void* dummy = NULL; 1.340 + ParameterSet ppb1 = ParamPickerMake(dummy); 1.341 + 1.342 + PolicyOpcode* op1 = opcode_maker.MakeOpAction(ASK_BROKER, kPolNone); 1.343 + EXPECT_TRUE(op1->IsAction()); 1.344 + EXPECT_EQ(ASK_BROKER, op1->Evaluate(&ppb1, 1, &mc1)); 1.345 +} 1.346 + 1.347 +} // namespace sandbox