| Index: sandbox/win/src/policy_engine_opcodes.cc
|
| diff --git a/sandbox/win/src/policy_engine_opcodes.cc b/sandbox/win/src/policy_engine_opcodes.cc
|
| deleted file mode 100644
|
| index 8dca0d9d621034b7d9eda2688465afa8c5048b7b..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/policy_engine_opcodes.cc
|
| +++ /dev/null
|
| @@ -1,446 +0,0 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "sandbox/win/src/policy_engine_opcodes.h"
|
| -
|
| -#include <stddef.h>
|
| -#include <stdint.h>
|
| -
|
| -#include "sandbox/win/src/sandbox_nt_types.h"
|
| -#include "sandbox/win/src/sandbox_types.h"
|
| -
|
| -namespace {
|
| -const unsigned short kMaxUniStrSize = 0xfffc / sizeof(wchar_t);
|
| -
|
| -bool InitStringUnicode(const wchar_t* source, size_t length,
|
| - UNICODE_STRING* ustring) {
|
| - if (length > kMaxUniStrSize) {
|
| - return false;
|
| - }
|
| - ustring->Buffer = const_cast<wchar_t*>(source);
|
| - ustring->Length = static_cast<USHORT>(length) * sizeof(wchar_t);
|
| - ustring->MaximumLength = (NULL != source) ?
|
| - ustring->Length + sizeof(wchar_t) : 0;
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace sandbox {
|
| -
|
| -SANDBOX_INTERCEPT NtExports g_nt;
|
| -
|
| -// Note: The opcodes are implemented as functions (as opposed to classes derived
|
| -// from PolicyOpcode) because you should not add more member variables to the
|
| -// PolicyOpcode class since it would cause object slicing on the target. So to
|
| -// enforce that (instead of just trusting the developer) the opcodes became
|
| -// just functions.
|
| -//
|
| -// In the code that follows I have keep the evaluation function and the factory
|
| -// function together to stress the close relationship between both. For example,
|
| -// only the factory method and the evaluation function know the stored argument
|
| -// order and meaning.
|
| -
|
| -template <int>
|
| -EvalResult OpcodeEval(PolicyOpcode* opcode, const ParameterSet* pp,
|
| - MatchContext* match);
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpAlwaysFalse:
|
| -// Does not require input parameter.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32_t options) {
|
| - return MakeBase(OP_ALWAYS_FALSE, options, -1);
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - return EVAL_FALSE;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpAlwaysTrue:
|
| -// Does not require input parameter.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32_t options) {
|
| - return MakeBase(OP_ALWAYS_TRUE, options, -1);
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - return EVAL_TRUE;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpAction:
|
| -// Does not require input parameter.
|
| -// Argument 0 contains the actual action to return.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action, uint32_t options) {
|
| - PolicyOpcode* opcode = MakeBase(OP_ACTION, options, 0);
|
| - if (NULL == opcode) return NULL;
|
| - opcode->SetArgument(0, action);
|
| - return opcode;
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - int action = 0;
|
| - opcode->GetArgument(0, &action);
|
| - return static_cast<EvalResult>(action);
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpNumberMatch:
|
| -// Requires a uint32_t or void* in selected_param
|
| -// Argument 0 is the stored number to match.
|
| -// Argument 1 is the C++ type of the 0th argument.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16_t selected_param,
|
| - uint32_t match,
|
| - uint32_t options) {
|
| - PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
|
| - if (NULL == opcode) return NULL;
|
| - opcode->SetArgument(0, match);
|
| - opcode->SetArgument(1, UINT32_TYPE);
|
| - return opcode;
|
| -}
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16_t selected_param,
|
| - const void* match,
|
| - uint32_t options) {
|
| - PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
|
| - if (NULL == opcode) return NULL;
|
| - opcode->SetArgument(0, match);
|
| - opcode->SetArgument(1, VOIDPTR_TYPE);
|
| - return opcode;
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_NUMBER_MATCH>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - uint32_t value_uint32 = 0;
|
| - if (param->Get(&value_uint32)) {
|
| - uint32_t match_uint32 = 0;
|
| - opcode->GetArgument(0, &match_uint32);
|
| - return (match_uint32 != value_uint32)? EVAL_FALSE : EVAL_TRUE;
|
| - } else {
|
| - const void* value_ptr = NULL;
|
| - if (param->Get(&value_ptr)) {
|
| - const void* match_ptr = NULL;
|
| - opcode->GetArgument(0, &match_ptr);
|
| - return (match_ptr != value_ptr)? EVAL_FALSE : EVAL_TRUE;
|
| - }
|
| - }
|
| - return EVAL_ERROR;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpNumberMatchRange
|
| -// Requires a uint32_t in selected_param.
|
| -// Argument 0 is the stored lower bound to match.
|
| -// Argument 1 is the stored upper bound to match.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16_t selected_param,
|
| - uint32_t lower_bound,
|
| - uint32_t upper_bound,
|
| - uint32_t options) {
|
| - if (lower_bound > upper_bound) {
|
| - return NULL;
|
| - }
|
| - PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH_RANGE, options,
|
| - selected_param);
|
| - if (NULL == opcode) return NULL;
|
| - opcode->SetArgument(0, lower_bound);
|
| - opcode->SetArgument(1, upper_bound);
|
| - return opcode;
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_NUMBER_MATCH_RANGE>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - uint32_t value = 0;
|
| - if (!param->Get(&value)) return EVAL_ERROR;
|
| -
|
| - uint32_t lower_bound = 0;
|
| - uint32_t upper_bound = 0;
|
| - opcode->GetArgument(0, &lower_bound);
|
| - opcode->GetArgument(1, &upper_bound);
|
| - return((lower_bound <= value) && (upper_bound >= value))?
|
| - EVAL_TRUE : EVAL_FALSE;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpNumberAndMatch:
|
| -// Requires a uint32_t in selected_param.
|
| -// Argument 0 is the stored number to match.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16_t selected_param,
|
| - uint32_t match,
|
| - uint32_t options) {
|
| - PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param);
|
| - if (NULL == opcode) return NULL;
|
| - opcode->SetArgument(0, match);
|
| - return opcode;
|
| -}
|
| -
|
| -template <>
|
| -EvalResult OpcodeEval<OP_NUMBER_AND_MATCH>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - uint32_t value = 0;
|
| - if (!param->Get(&value)) return EVAL_ERROR;
|
| -
|
| - uint32_t number = 0;
|
| - opcode->GetArgument(0, &number);
|
| - return (number & value)? EVAL_TRUE : EVAL_FALSE;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode OpWStringMatch:
|
| -// Requires a wchar_t* in selected_param.
|
| -// Argument 0 is the byte displacement of the stored string.
|
| -// Argument 1 is the lenght in chars of the stored string.
|
| -// Argument 2 is the offset to apply on the input string. It has special values.
|
| -// as noted in the header file.
|
| -// Argument 3 is the string matching options.
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16_t selected_param,
|
| - const wchar_t* match_str,
|
| - int start_position,
|
| - StringMatchOptions match_opts,
|
| - uint32_t options) {
|
| - if (NULL == match_str) {
|
| - return NULL;
|
| - }
|
| - if ('\0' == match_str[0]) {
|
| - return NULL;
|
| - }
|
| -
|
| - int lenght = lstrlenW(match_str);
|
| -
|
| - PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param);
|
| - if (NULL == opcode) {
|
| - return NULL;
|
| - }
|
| - ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str)+1);
|
| - if (0 == delta_str) {
|
| - return NULL;
|
| - }
|
| - opcode->SetArgument(0, delta_str);
|
| - opcode->SetArgument(1, lenght);
|
| - opcode->SetArgument(2, start_position);
|
| - opcode->SetArgument(3, match_opts);
|
| - return opcode;
|
| -}
|
| -
|
| -template<>
|
| -EvalResult OpcodeEval<OP_WSTRING_MATCH>(PolicyOpcode* opcode,
|
| - const ParameterSet* param,
|
| - MatchContext* context) {
|
| - if (NULL == context) {
|
| - return EVAL_ERROR;
|
| - }
|
| - const wchar_t* source_str = NULL;
|
| - if (!param->Get(&source_str)) return EVAL_ERROR;
|
| -
|
| - int start_position = 0;
|
| - int match_len = 0;
|
| - unsigned int match_opts = 0;
|
| - opcode->GetArgument(1, &match_len);
|
| - opcode->GetArgument(2, &start_position);
|
| - opcode->GetArgument(3, &match_opts);
|
| -
|
| - const wchar_t* match_str = opcode->GetRelativeString(0);
|
| - // Advance the source string to the last successfully evaluated position
|
| - // according to the match context.
|
| - source_str = &source_str[context->position];
|
| - int source_len = static_cast<int>(g_nt.wcslen(source_str));
|
| -
|
| - if (0 == source_len) {
|
| - // If we reached the end of the source string there is nothing we can
|
| - // match against.
|
| - return EVAL_FALSE;
|
| - }
|
| - if (match_len > source_len) {
|
| - // There can't be a positive match when the target string is bigger than
|
| - // the source string
|
| - return EVAL_FALSE;
|
| - }
|
| -
|
| - BOOLEAN case_sensitive = (match_opts & CASE_INSENSITIVE) ? TRUE : FALSE;
|
| -
|
| - // We have three cases, depending on the value of start_pos:
|
| - // Case 1. We skip N characters and compare once.
|
| - // Case 2: We skip to the end and compare once.
|
| - // Case 3: We match the first substring (if we find any).
|
| - if (start_position >= 0) {
|
| - if (kSeekToEnd == start_position) {
|
| - start_position = source_len - match_len;
|
| - } else if (match_opts & EXACT_LENGHT) {
|
| - // A sub-case of case 3 is when the EXACT_LENGHT flag is on
|
| - // the match needs to be not just substring but full match.
|
| - if ((match_len + start_position) != source_len) {
|
| - return EVAL_FALSE;
|
| - }
|
| - }
|
| -
|
| - // Advance start_pos characters. Warning! this does not consider
|
| - // utf16 encodings (surrogate pairs) or other Unicode 'features'.
|
| - source_str += start_position;
|
| -
|
| - // Since we skipped, lets reevaluate just the lengths again.
|
| - if ((match_len + start_position) > source_len) {
|
| - return EVAL_FALSE;
|
| - }
|
| -
|
| - UNICODE_STRING match_ustr;
|
| - UNICODE_STRING source_ustr;
|
| - if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
|
| - !InitStringUnicode(source_str, match_len, &source_ustr))
|
| - return EVAL_ERROR;
|
| -
|
| - if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
|
| - case_sensitive)) {
|
| - // Match! update the match context.
|
| - context->position += start_position + match_len;
|
| - return EVAL_TRUE;
|
| - } else {
|
| - return EVAL_FALSE;
|
| - }
|
| - } else if (start_position < 0) {
|
| - UNICODE_STRING match_ustr;
|
| - UNICODE_STRING source_ustr;
|
| - if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
|
| - !InitStringUnicode(source_str, match_len, &source_ustr))
|
| - return EVAL_ERROR;
|
| -
|
| - do {
|
| - if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
|
| - case_sensitive)) {
|
| - // Match! update the match context.
|
| - context->position += (source_ustr.Buffer - source_str) + match_len;
|
| - return EVAL_TRUE;
|
| - }
|
| - ++source_ustr.Buffer;
|
| - --source_len;
|
| - } while (source_len >= match_len);
|
| - }
|
| - return EVAL_FALSE;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// OpcodeMaker (other member functions).
|
| -
|
| -PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
|
| - uint32_t options,
|
| - int16_t selected_param) {
|
| - if (memory_size() < sizeof(PolicyOpcode)) {
|
| - return NULL;
|
| - }
|
| -
|
| - // Create opcode using placement-new on the buffer memory.
|
| - PolicyOpcode* opcode = new(memory_top_) PolicyOpcode();
|
| -
|
| - // Fill in the standard fields, that every opcode has.
|
| - memory_top_ += sizeof(PolicyOpcode);
|
| - opcode->opcode_id_ = opcode_id;
|
| - opcode->SetOptions(options);
|
| - opcode->parameter_ = selected_param;
|
| - return opcode;
|
| -}
|
| -
|
| -ptrdiff_t OpcodeFactory::AllocRelative(void* start, const wchar_t* str,
|
| - size_t lenght) {
|
| - size_t bytes = lenght * sizeof(wchar_t);
|
| - if (memory_size() < bytes) {
|
| - return 0;
|
| - }
|
| - memory_bottom_ -= bytes;
|
| - if (reinterpret_cast<UINT_PTR>(memory_bottom_) & 1) {
|
| - // TODO(cpu) replace this for something better.
|
| - ::DebugBreak();
|
| - }
|
| - memcpy(memory_bottom_, str, bytes);
|
| - ptrdiff_t delta = memory_bottom_ - reinterpret_cast<char*>(start);
|
| - return delta;
|
| -}
|
| -
|
| -//////////////////////////////////////////////////////////////////////////////
|
| -// Opcode evaluation dispatchers.
|
| -
|
| -// This function is the one and only entry for evaluating any opcode. It is
|
| -// in charge of applying any relevant opcode options and calling EvaluateInner
|
| -// were the actual dispatch-by-id is made. It would seem at first glance that
|
| -// the dispatch should be done by virtual function (vtable) calls but you have
|
| -// to remember that the opcodes are made in the broker process and copied as
|
| -// raw memory to the target process.
|
| -
|
| -EvalResult PolicyOpcode::Evaluate(const ParameterSet* call_params,
|
| - size_t param_count, MatchContext* match) {
|
| - if (NULL == call_params) {
|
| - return EVAL_ERROR;
|
| - }
|
| - const ParameterSet* selected_param = NULL;
|
| - if (parameter_ >= 0) {
|
| - if (static_cast<size_t>(parameter_) >= param_count) {
|
| - return EVAL_ERROR;
|
| - }
|
| - selected_param = &call_params[parameter_];
|
| - }
|
| - EvalResult result = EvaluateHelper(selected_param, match);
|
| -
|
| - // Apply the general options regardless of the particular type of opcode.
|
| - if (kPolNone == options_) {
|
| - return result;
|
| - }
|
| -
|
| - if (options_ & kPolNegateEval) {
|
| - if (EVAL_TRUE == result) {
|
| - result = EVAL_FALSE;
|
| - } else if (EVAL_FALSE == result) {
|
| - result = EVAL_TRUE;
|
| - } else if (EVAL_ERROR != result) {
|
| - result = EVAL_ERROR;
|
| - }
|
| - }
|
| - if (NULL != match) {
|
| - if (options_ & kPolClearContext) {
|
| - match->Clear();
|
| - }
|
| - if (options_ & kPolUseOREval) {
|
| - match->options = kPolUseOREval;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -#define OPCODE_EVAL(op, x, y, z) case op: return OpcodeEval<op>(x, y, z)
|
| -
|
| -EvalResult PolicyOpcode::EvaluateHelper(const ParameterSet* parameters,
|
| - MatchContext* match) {
|
| - switch (opcode_id_) {
|
| - OPCODE_EVAL(OP_ALWAYS_FALSE, this, parameters, match);
|
| - OPCODE_EVAL(OP_ALWAYS_TRUE, this, parameters, match);
|
| - OPCODE_EVAL(OP_NUMBER_MATCH, this, parameters, match);
|
| - OPCODE_EVAL(OP_NUMBER_MATCH_RANGE, this, parameters, match);
|
| - OPCODE_EVAL(OP_NUMBER_AND_MATCH, this, parameters, match);
|
| - OPCODE_EVAL(OP_WSTRING_MATCH, this, parameters, match);
|
| - OPCODE_EVAL(OP_ACTION, this, parameters, match);
|
| - default:
|
| - return EVAL_ERROR;
|
| - }
|
| -}
|
| -
|
| -#undef OPCODE_EVAL
|
| -
|
| -} // namespace sandbox
|
|
|