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