michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "sandbox/win/src/policy_engine_processor.h" michael@0: michael@0: namespace sandbox { michael@0: michael@0: void PolicyProcessor::SetInternalState(size_t index, EvalResult result) { michael@0: state_.current_index_ = index; michael@0: state_.current_result_ = result; michael@0: } michael@0: michael@0: EvalResult PolicyProcessor::GetAction() const { michael@0: return state_.current_result_; michael@0: } michael@0: michael@0: // Decides if an opcode can be skipped (not evaluated) or not. The function michael@0: // takes as inputs the opcode and the current evaluation context and returns michael@0: // true if the opcode should be skipped or not and also can set keep_skipping michael@0: // to false to signal that the current instruction should be skipped but not michael@0: // the next after the current one. michael@0: bool SkipOpcode(const PolicyOpcode& opcode, MatchContext* context, michael@0: bool* keep_skipping) { michael@0: if (opcode.IsAction()) { michael@0: uint32 options = context->options; michael@0: context->Clear(); michael@0: *keep_skipping = false; michael@0: return (kPolUseOREval != options); michael@0: } michael@0: *keep_skipping = true; michael@0: return true; michael@0: } michael@0: michael@0: PolicyResult PolicyProcessor::Evaluate(uint32 options, michael@0: ParameterSet* parameters, michael@0: size_t param_count) { michael@0: if (NULL == policy_) { michael@0: return NO_POLICY_MATCH; michael@0: } michael@0: if (0 == policy_->opcode_count) { michael@0: return NO_POLICY_MATCH; michael@0: } michael@0: if (!(kShortEval & options)) { michael@0: return POLICY_ERROR; michael@0: } michael@0: michael@0: MatchContext context; michael@0: bool evaluation = false; michael@0: bool skip_group = false; michael@0: SetInternalState(0, EVAL_FALSE); michael@0: size_t count = policy_->opcode_count; michael@0: michael@0: // Loop over all the opcodes Evaluating in sequence. Since we only support michael@0: // short circuit evaluation, we stop as soon as we find an 'action' opcode michael@0: // and the current evaluation is true. michael@0: // michael@0: // Skipping opcodes can happen when we are in AND mode (!kPolUseOREval) and michael@0: // have got EVAL_FALSE or when we are in OR mode (kPolUseOREval) and got michael@0: // EVAL_TRUE. Skipping will stop at the next action opcode or at the opcode michael@0: // after the action depending on kPolUseOREval. michael@0: michael@0: for (size_t ix = 0; ix != count; ++ix) { michael@0: PolicyOpcode& opcode = policy_->opcodes[ix]; michael@0: // Skipping block. michael@0: if (skip_group) { michael@0: if (SkipOpcode(opcode, &context, &skip_group)) { michael@0: continue; michael@0: } michael@0: } michael@0: // Evaluation block. michael@0: EvalResult result = opcode.Evaluate(parameters, param_count, &context); michael@0: switch (result) { michael@0: case EVAL_FALSE: michael@0: evaluation = false; michael@0: if (kPolUseOREval != context.options) { michael@0: skip_group = true; michael@0: } michael@0: break; michael@0: case EVAL_ERROR: michael@0: if (kStopOnErrors & options) { michael@0: return POLICY_ERROR; michael@0: } michael@0: break; michael@0: case EVAL_TRUE: michael@0: evaluation = true; michael@0: if (kPolUseOREval == context.options) { michael@0: skip_group = true; michael@0: } michael@0: break; michael@0: default: michael@0: // We have evaluated an action. michael@0: SetInternalState(ix, result); michael@0: return POLICY_MATCH; michael@0: } michael@0: } michael@0: michael@0: if (evaluation) { michael@0: // Reaching the end of the policy with a positive evaluation is probably michael@0: // an error: we did not find a final action opcode? michael@0: return POLICY_ERROR; michael@0: } michael@0: return NO_POLICY_MATCH; michael@0: } michael@0: michael@0: michael@0: } // namespace sandbox