security/sandbox/win/src/policy_opcodes_unittest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial