security/sandbox/win/src/policy_opcodes_unittest.cc

changeset 0
6474c204b198
     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

mercurial