| 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 "sandbox/win/src/policy_engine_opcodes.h" |  | 
|    6  |  | 
|    7 #include <stddef.h> |  | 
|    8 #include <stdint.h> |  | 
|    9  |  | 
|   10 #include "sandbox/win/src/sandbox_nt_types.h" |  | 
|   11 #include "sandbox/win/src/sandbox_types.h" |  | 
|   12  |  | 
|   13 namespace { |  | 
|   14 const unsigned short kMaxUniStrSize = 0xfffc / sizeof(wchar_t); |  | 
|   15  |  | 
|   16 bool InitStringUnicode(const wchar_t* source, size_t length, |  | 
|   17                        UNICODE_STRING* ustring) { |  | 
|   18   if (length > kMaxUniStrSize) { |  | 
|   19     return false; |  | 
|   20   } |  | 
|   21   ustring->Buffer = const_cast<wchar_t*>(source); |  | 
|   22   ustring->Length = static_cast<USHORT>(length) * sizeof(wchar_t); |  | 
|   23   ustring->MaximumLength = (NULL != source) ? |  | 
|   24                                 ustring->Length + sizeof(wchar_t) : 0; |  | 
|   25   return true; |  | 
|   26 } |  | 
|   27  |  | 
|   28 }  // namespace |  | 
|   29  |  | 
|   30 namespace sandbox { |  | 
|   31  |  | 
|   32 SANDBOX_INTERCEPT NtExports g_nt; |  | 
|   33  |  | 
|   34 // Note: The opcodes are implemented as functions (as opposed to classes derived |  | 
|   35 // from PolicyOpcode) because you should not add more member variables to the |  | 
|   36 // PolicyOpcode class since it would cause object slicing on the target. So to |  | 
|   37 // enforce that (instead of just trusting the developer) the opcodes became |  | 
|   38 // just functions. |  | 
|   39 // |  | 
|   40 // In the code that follows I have keep the evaluation function and the factory |  | 
|   41 // function together to stress the close relationship between both. For example, |  | 
|   42 // only the factory method and the evaluation function know the stored argument |  | 
|   43 // order and meaning. |  | 
|   44  |  | 
|   45 template <int> |  | 
|   46 EvalResult OpcodeEval(PolicyOpcode* opcode, const ParameterSet* pp, |  | 
|   47                       MatchContext* match); |  | 
|   48  |  | 
|   49 ////////////////////////////////////////////////////////////////////////////// |  | 
|   50 // Opcode OpAlwaysFalse: |  | 
|   51 // Does not require input parameter. |  | 
|   52  |  | 
|   53 PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32_t options) { |  | 
|   54   return MakeBase(OP_ALWAYS_FALSE, options, -1); |  | 
|   55 } |  | 
|   56  |  | 
|   57 template <> |  | 
|   58 EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode, |  | 
|   59                                        const ParameterSet* param, |  | 
|   60                                        MatchContext* context) { |  | 
|   61   return EVAL_FALSE; |  | 
|   62 } |  | 
|   63  |  | 
|   64 ////////////////////////////////////////////////////////////////////////////// |  | 
|   65 // Opcode OpAlwaysTrue: |  | 
|   66 // Does not require input parameter. |  | 
|   67  |  | 
|   68 PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32_t options) { |  | 
|   69   return MakeBase(OP_ALWAYS_TRUE, options, -1); |  | 
|   70 } |  | 
|   71  |  | 
|   72 template <> |  | 
|   73 EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode, |  | 
|   74                                       const ParameterSet* param, |  | 
|   75                                       MatchContext* context) { |  | 
|   76   return EVAL_TRUE; |  | 
|   77 } |  | 
|   78  |  | 
|   79 ////////////////////////////////////////////////////////////////////////////// |  | 
|   80 // Opcode OpAction: |  | 
|   81 // Does not require input parameter. |  | 
|   82 // Argument 0 contains the actual action to return. |  | 
|   83  |  | 
|   84 PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action, uint32_t options) { |  | 
|   85   PolicyOpcode* opcode = MakeBase(OP_ACTION, options, 0); |  | 
|   86   if (NULL == opcode) return NULL; |  | 
|   87   opcode->SetArgument(0, action); |  | 
|   88   return opcode; |  | 
|   89 } |  | 
|   90  |  | 
|   91 template <> |  | 
|   92 EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode, |  | 
|   93                                  const ParameterSet* param, |  | 
|   94                                  MatchContext* context) { |  | 
|   95   int action = 0; |  | 
|   96   opcode->GetArgument(0, &action); |  | 
|   97   return static_cast<EvalResult>(action); |  | 
|   98 } |  | 
|   99  |  | 
|  100 ////////////////////////////////////////////////////////////////////////////// |  | 
|  101 // Opcode OpNumberMatch: |  | 
|  102 // Requires a uint32_t or void* in selected_param |  | 
|  103 // Argument 0 is the stored number to match. |  | 
|  104 // Argument 1 is the C++ type of the 0th argument. |  | 
|  105  |  | 
|  106 PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16_t selected_param, |  | 
|  107                                                uint32_t match, |  | 
|  108                                                uint32_t options) { |  | 
|  109   PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param); |  | 
|  110   if (NULL == opcode) return NULL; |  | 
|  111   opcode->SetArgument(0, match); |  | 
|  112   opcode->SetArgument(1, UINT32_TYPE); |  | 
|  113   return opcode; |  | 
|  114 } |  | 
|  115  |  | 
|  116 PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16_t selected_param, |  | 
|  117                                                 const void* match, |  | 
|  118                                                 uint32_t options) { |  | 
|  119   PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param); |  | 
|  120   if (NULL == opcode) return NULL; |  | 
|  121   opcode->SetArgument(0, match); |  | 
|  122   opcode->SetArgument(1, VOIDPTR_TYPE); |  | 
|  123   return opcode; |  | 
|  124 } |  | 
|  125  |  | 
|  126 template <> |  | 
|  127 EvalResult OpcodeEval<OP_NUMBER_MATCH>(PolicyOpcode* opcode, |  | 
|  128                                        const ParameterSet* param, |  | 
|  129                                        MatchContext* context) { |  | 
|  130   uint32_t value_uint32 = 0; |  | 
|  131   if (param->Get(&value_uint32)) { |  | 
|  132     uint32_t match_uint32 = 0; |  | 
|  133     opcode->GetArgument(0, &match_uint32); |  | 
|  134     return (match_uint32 != value_uint32)? EVAL_FALSE : EVAL_TRUE; |  | 
|  135   } else { |  | 
|  136     const void* value_ptr = NULL; |  | 
|  137     if (param->Get(&value_ptr)) { |  | 
|  138       const void* match_ptr = NULL; |  | 
|  139       opcode->GetArgument(0, &match_ptr); |  | 
|  140       return (match_ptr != value_ptr)? EVAL_FALSE : EVAL_TRUE; |  | 
|  141     } |  | 
|  142   } |  | 
|  143   return EVAL_ERROR; |  | 
|  144 } |  | 
|  145  |  | 
|  146 ////////////////////////////////////////////////////////////////////////////// |  | 
|  147 // Opcode OpNumberMatchRange |  | 
|  148 // Requires a uint32_t in selected_param. |  | 
|  149 // Argument 0 is the stored lower bound to match. |  | 
|  150 // Argument 1 is the stored upper bound to match. |  | 
|  151  |  | 
|  152 PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16_t selected_param, |  | 
|  153                                                     uint32_t lower_bound, |  | 
|  154                                                     uint32_t upper_bound, |  | 
|  155                                                     uint32_t options) { |  | 
|  156   if (lower_bound > upper_bound) { |  | 
|  157     return NULL; |  | 
|  158   } |  | 
|  159   PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH_RANGE, options, |  | 
|  160                                   selected_param); |  | 
|  161   if (NULL == opcode) return NULL; |  | 
|  162   opcode->SetArgument(0, lower_bound); |  | 
|  163   opcode->SetArgument(1, upper_bound); |  | 
|  164   return opcode; |  | 
|  165 } |  | 
|  166  |  | 
|  167 template <> |  | 
|  168 EvalResult OpcodeEval<OP_NUMBER_MATCH_RANGE>(PolicyOpcode* opcode, |  | 
|  169                                              const ParameterSet* param, |  | 
|  170                                              MatchContext* context) { |  | 
|  171   uint32_t value = 0; |  | 
|  172   if (!param->Get(&value)) return EVAL_ERROR; |  | 
|  173  |  | 
|  174   uint32_t lower_bound = 0; |  | 
|  175   uint32_t upper_bound = 0; |  | 
|  176   opcode->GetArgument(0, &lower_bound); |  | 
|  177   opcode->GetArgument(1, &upper_bound); |  | 
|  178   return((lower_bound <= value) && (upper_bound >= value))? |  | 
|  179     EVAL_TRUE : EVAL_FALSE; |  | 
|  180 } |  | 
|  181  |  | 
|  182 ////////////////////////////////////////////////////////////////////////////// |  | 
|  183 // Opcode OpNumberAndMatch: |  | 
|  184 // Requires a uint32_t in selected_param. |  | 
|  185 // Argument 0 is the stored number to match. |  | 
|  186  |  | 
|  187 PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16_t selected_param, |  | 
|  188                                                   uint32_t match, |  | 
|  189                                                   uint32_t options) { |  | 
|  190   PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param); |  | 
|  191   if (NULL == opcode) return NULL; |  | 
|  192   opcode->SetArgument(0, match); |  | 
|  193   return opcode; |  | 
|  194 } |  | 
|  195  |  | 
|  196 template <> |  | 
|  197 EvalResult OpcodeEval<OP_NUMBER_AND_MATCH>(PolicyOpcode* opcode, |  | 
|  198                                            const ParameterSet* param, |  | 
|  199                                            MatchContext* context) { |  | 
|  200   uint32_t value = 0; |  | 
|  201   if (!param->Get(&value)) return EVAL_ERROR; |  | 
|  202  |  | 
|  203   uint32_t number = 0; |  | 
|  204   opcode->GetArgument(0, &number); |  | 
|  205   return (number & value)? EVAL_TRUE : EVAL_FALSE; |  | 
|  206 } |  | 
|  207  |  | 
|  208 ////////////////////////////////////////////////////////////////////////////// |  | 
|  209 // Opcode OpWStringMatch: |  | 
|  210 // Requires a wchar_t* in selected_param. |  | 
|  211 // Argument 0 is the byte displacement of the stored string. |  | 
|  212 // Argument 1 is the lenght in chars of the stored string. |  | 
|  213 // Argument 2 is the offset to apply on the input string. It has special values. |  | 
|  214 // as noted in the header file. |  | 
|  215 // Argument 3 is the string matching options. |  | 
|  216  |  | 
|  217 PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16_t selected_param, |  | 
|  218                                                 const wchar_t* match_str, |  | 
|  219                                                 int start_position, |  | 
|  220                                                 StringMatchOptions match_opts, |  | 
|  221                                                 uint32_t options) { |  | 
|  222   if (NULL == match_str) { |  | 
|  223     return NULL; |  | 
|  224   } |  | 
|  225   if ('\0' == match_str[0]) { |  | 
|  226     return NULL; |  | 
|  227   } |  | 
|  228  |  | 
|  229   int lenght = lstrlenW(match_str); |  | 
|  230  |  | 
|  231   PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param); |  | 
|  232   if (NULL == opcode) { |  | 
|  233     return NULL; |  | 
|  234   } |  | 
|  235   ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str)+1); |  | 
|  236   if (0 == delta_str) { |  | 
|  237     return NULL; |  | 
|  238   } |  | 
|  239   opcode->SetArgument(0, delta_str); |  | 
|  240   opcode->SetArgument(1, lenght); |  | 
|  241   opcode->SetArgument(2, start_position); |  | 
|  242   opcode->SetArgument(3, match_opts); |  | 
|  243   return opcode; |  | 
|  244 } |  | 
|  245  |  | 
|  246 template<> |  | 
|  247 EvalResult OpcodeEval<OP_WSTRING_MATCH>(PolicyOpcode* opcode, |  | 
|  248                                         const ParameterSet* param, |  | 
|  249                                         MatchContext* context) { |  | 
|  250   if (NULL == context) { |  | 
|  251     return EVAL_ERROR; |  | 
|  252   } |  | 
|  253   const wchar_t* source_str = NULL; |  | 
|  254   if (!param->Get(&source_str)) return EVAL_ERROR; |  | 
|  255  |  | 
|  256   int start_position = 0; |  | 
|  257   int match_len = 0; |  | 
|  258   unsigned int match_opts = 0; |  | 
|  259   opcode->GetArgument(1, &match_len); |  | 
|  260   opcode->GetArgument(2, &start_position); |  | 
|  261   opcode->GetArgument(3, &match_opts); |  | 
|  262  |  | 
|  263   const wchar_t* match_str = opcode->GetRelativeString(0); |  | 
|  264   // Advance the source string to the last successfully evaluated position |  | 
|  265   // according to the match context. |  | 
|  266   source_str = &source_str[context->position]; |  | 
|  267   int source_len  = static_cast<int>(g_nt.wcslen(source_str)); |  | 
|  268  |  | 
|  269   if (0 == source_len) { |  | 
|  270     // If we reached the end of the source string there is nothing we can |  | 
|  271     // match against. |  | 
|  272     return EVAL_FALSE; |  | 
|  273   } |  | 
|  274   if (match_len > source_len) { |  | 
|  275     // There can't be a positive match when the target string is bigger than |  | 
|  276     // the source string |  | 
|  277     return EVAL_FALSE; |  | 
|  278   } |  | 
|  279  |  | 
|  280   BOOLEAN case_sensitive = (match_opts & CASE_INSENSITIVE) ? TRUE : FALSE; |  | 
|  281  |  | 
|  282   // We have three cases, depending on the value of start_pos: |  | 
|  283   // Case 1. We skip N characters and compare once. |  | 
|  284   // Case 2: We skip to the end and compare once. |  | 
|  285   // Case 3: We match the first substring (if we find any). |  | 
|  286   if (start_position >= 0) { |  | 
|  287     if (kSeekToEnd == start_position) { |  | 
|  288         start_position = source_len - match_len; |  | 
|  289     } else if (match_opts & EXACT_LENGHT) { |  | 
|  290         // A sub-case of case 3 is when the EXACT_LENGHT flag is on |  | 
|  291         // the match needs to be not just substring but full match. |  | 
|  292         if ((match_len + start_position) != source_len) { |  | 
|  293           return EVAL_FALSE; |  | 
|  294         } |  | 
|  295     } |  | 
|  296  |  | 
|  297     // Advance start_pos characters. Warning! this does not consider |  | 
|  298     // utf16 encodings (surrogate pairs) or other Unicode 'features'. |  | 
|  299     source_str += start_position; |  | 
|  300  |  | 
|  301     // Since we skipped, lets reevaluate just the lengths again. |  | 
|  302     if ((match_len + start_position) > source_len) { |  | 
|  303       return EVAL_FALSE; |  | 
|  304     } |  | 
|  305  |  | 
|  306     UNICODE_STRING match_ustr; |  | 
|  307     UNICODE_STRING source_ustr; |  | 
|  308     if (!InitStringUnicode(match_str, match_len, &match_ustr) || |  | 
|  309         !InitStringUnicode(source_str, match_len, &source_ustr)) |  | 
|  310       return EVAL_ERROR; |  | 
|  311  |  | 
|  312     if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr, |  | 
|  313                                           case_sensitive)) { |  | 
|  314       // Match! update the match context. |  | 
|  315       context->position += start_position + match_len; |  | 
|  316       return EVAL_TRUE; |  | 
|  317     } else { |  | 
|  318       return EVAL_FALSE; |  | 
|  319     } |  | 
|  320   } else if (start_position < 0) { |  | 
|  321     UNICODE_STRING match_ustr; |  | 
|  322     UNICODE_STRING source_ustr; |  | 
|  323     if (!InitStringUnicode(match_str, match_len, &match_ustr) || |  | 
|  324         !InitStringUnicode(source_str, match_len, &source_ustr)) |  | 
|  325       return EVAL_ERROR; |  | 
|  326  |  | 
|  327     do { |  | 
|  328       if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr, |  | 
|  329                                             case_sensitive)) { |  | 
|  330         // Match! update the match context. |  | 
|  331         context->position += (source_ustr.Buffer - source_str) + match_len; |  | 
|  332         return EVAL_TRUE; |  | 
|  333       } |  | 
|  334       ++source_ustr.Buffer; |  | 
|  335       --source_len; |  | 
|  336     } while (source_len >= match_len); |  | 
|  337   } |  | 
|  338   return EVAL_FALSE; |  | 
|  339 } |  | 
|  340  |  | 
|  341 ////////////////////////////////////////////////////////////////////////////// |  | 
|  342 // OpcodeMaker (other member functions). |  | 
|  343  |  | 
|  344 PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id, |  | 
|  345                                       uint32_t options, |  | 
|  346                                       int16_t selected_param) { |  | 
|  347   if (memory_size() < sizeof(PolicyOpcode)) { |  | 
|  348     return NULL; |  | 
|  349   } |  | 
|  350  |  | 
|  351   // Create opcode using placement-new on the buffer memory. |  | 
|  352   PolicyOpcode* opcode = new(memory_top_) PolicyOpcode(); |  | 
|  353  |  | 
|  354   // Fill in the standard fields, that every opcode has. |  | 
|  355   memory_top_ += sizeof(PolicyOpcode); |  | 
|  356   opcode->opcode_id_ = opcode_id; |  | 
|  357   opcode->SetOptions(options); |  | 
|  358   opcode->parameter_ = selected_param; |  | 
|  359   return opcode; |  | 
|  360 } |  | 
|  361  |  | 
|  362 ptrdiff_t OpcodeFactory::AllocRelative(void* start, const wchar_t* str, |  | 
|  363                                        size_t lenght) { |  | 
|  364   size_t bytes = lenght * sizeof(wchar_t); |  | 
|  365   if (memory_size() < bytes) { |  | 
|  366     return 0; |  | 
|  367   } |  | 
|  368   memory_bottom_ -= bytes; |  | 
|  369   if (reinterpret_cast<UINT_PTR>(memory_bottom_) & 1) { |  | 
|  370     // TODO(cpu) replace this for something better. |  | 
|  371     ::DebugBreak(); |  | 
|  372   } |  | 
|  373   memcpy(memory_bottom_, str, bytes); |  | 
|  374   ptrdiff_t delta = memory_bottom_ - reinterpret_cast<char*>(start); |  | 
|  375   return delta; |  | 
|  376 } |  | 
|  377  |  | 
|  378 ////////////////////////////////////////////////////////////////////////////// |  | 
|  379 // Opcode evaluation dispatchers. |  | 
|  380  |  | 
|  381 // This function is the one and only entry for evaluating any opcode. It is |  | 
|  382 // in charge of applying any relevant opcode options and calling EvaluateInner |  | 
|  383 // were the actual dispatch-by-id is made. It would seem at first glance that |  | 
|  384 // the dispatch should be done by virtual function (vtable) calls but you have |  | 
|  385 // to remember that the opcodes are made in the broker process and copied as |  | 
|  386 // raw memory to the target process. |  | 
|  387  |  | 
|  388 EvalResult PolicyOpcode::Evaluate(const ParameterSet* call_params, |  | 
|  389                                   size_t param_count, MatchContext* match) { |  | 
|  390   if (NULL == call_params) { |  | 
|  391     return EVAL_ERROR; |  | 
|  392   } |  | 
|  393   const ParameterSet* selected_param = NULL; |  | 
|  394   if (parameter_ >= 0) { |  | 
|  395     if (static_cast<size_t>(parameter_) >= param_count) { |  | 
|  396       return EVAL_ERROR; |  | 
|  397     } |  | 
|  398     selected_param = &call_params[parameter_]; |  | 
|  399   } |  | 
|  400   EvalResult result = EvaluateHelper(selected_param, match); |  | 
|  401  |  | 
|  402   // Apply the general options regardless of the particular type of opcode. |  | 
|  403   if (kPolNone == options_) { |  | 
|  404     return result; |  | 
|  405   } |  | 
|  406  |  | 
|  407   if (options_ & kPolNegateEval) { |  | 
|  408     if (EVAL_TRUE == result) { |  | 
|  409       result = EVAL_FALSE; |  | 
|  410     } else if (EVAL_FALSE == result) { |  | 
|  411       result = EVAL_TRUE; |  | 
|  412     } else if (EVAL_ERROR != result) { |  | 
|  413       result = EVAL_ERROR; |  | 
|  414     } |  | 
|  415   } |  | 
|  416   if (NULL != match) { |  | 
|  417     if (options_ & kPolClearContext) { |  | 
|  418       match->Clear(); |  | 
|  419     } |  | 
|  420     if (options_ & kPolUseOREval) { |  | 
|  421       match->options = kPolUseOREval; |  | 
|  422     } |  | 
|  423   } |  | 
|  424   return result; |  | 
|  425 } |  | 
|  426  |  | 
|  427 #define OPCODE_EVAL(op, x, y, z) case op: return OpcodeEval<op>(x, y, z) |  | 
|  428  |  | 
|  429 EvalResult PolicyOpcode::EvaluateHelper(const ParameterSet* parameters, |  | 
|  430                                        MatchContext* match) { |  | 
|  431   switch (opcode_id_) { |  | 
|  432     OPCODE_EVAL(OP_ALWAYS_FALSE, this, parameters, match); |  | 
|  433     OPCODE_EVAL(OP_ALWAYS_TRUE, this, parameters, match); |  | 
|  434     OPCODE_EVAL(OP_NUMBER_MATCH, this, parameters, match); |  | 
|  435     OPCODE_EVAL(OP_NUMBER_MATCH_RANGE, this, parameters, match); |  | 
|  436     OPCODE_EVAL(OP_NUMBER_AND_MATCH, this, parameters, match); |  | 
|  437     OPCODE_EVAL(OP_WSTRING_MATCH, this, parameters, match); |  | 
|  438     OPCODE_EVAL(OP_ACTION, this, parameters, match); |  | 
|  439     default: |  | 
|  440       return EVAL_ERROR; |  | 
|  441   } |  | 
|  442 } |  | 
|  443  |  | 
|  444 #undef OPCODE_EVAL |  | 
|  445  |  | 
|  446 }  // namespace sandbox |  | 
| OLD | NEW |