Home | History | Annotate | Download | only in src
      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