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_processor.h"
6
7namespace sandbox {
8
9void PolicyProcessor::SetInternalState(size_t index, EvalResult result) {
10  state_.current_index_ = index;
11  state_.current_result_ = result;
12}
13
14EvalResult PolicyProcessor::GetAction() const {
15  return state_.current_result_;
16}
17
18// Decides if an opcode can be skipped (not evaluated) or not. The function
19// takes as inputs the opcode and the current evaluation context and returns
20// true if the opcode should be skipped or not and also can set keep_skipping
21// to false to signal that the current instruction should be skipped but not
22// the next after the current one.
23bool SkipOpcode(const PolicyOpcode& opcode, MatchContext* context,
24                bool* keep_skipping) {
25  if (opcode.IsAction()) {
26    uint32 options = context->options;
27    context->Clear();
28    *keep_skipping = false;
29    return (kPolUseOREval != options);
30  }
31  *keep_skipping = true;
32  return true;
33}
34
35PolicyResult PolicyProcessor::Evaluate(uint32 options,
36                                       ParameterSet* parameters,
37                                       size_t param_count) {
38  if (NULL == policy_) {
39    return NO_POLICY_MATCH;
40  }
41  if (0 == policy_->opcode_count) {
42    return NO_POLICY_MATCH;
43  }
44  if (!(kShortEval & options)) {
45    return POLICY_ERROR;
46  }
47
48  MatchContext context;
49  bool evaluation = false;
50  bool skip_group = false;
51  SetInternalState(0, EVAL_FALSE);
52  size_t count = policy_->opcode_count;
53
54  // Loop over all the opcodes Evaluating in sequence. Since we only support
55  // short circuit evaluation, we stop as soon as we find an 'action' opcode
56  // and the current evaluation is true.
57  //
58  // Skipping opcodes can happen when we are in AND mode (!kPolUseOREval) and
59  // have got EVAL_FALSE or when we are in OR mode (kPolUseOREval) and got
60  // EVAL_TRUE. Skipping will stop at the next action opcode or at the opcode
61  // after the action depending on kPolUseOREval.
62
63  for (size_t ix = 0; ix != count; ++ix) {
64    PolicyOpcode& opcode = policy_->opcodes[ix];
65    // Skipping block.
66    if (skip_group) {
67      if (SkipOpcode(opcode, &context, &skip_group)) {
68        continue;
69      }
70    }
71    // Evaluation block.
72    EvalResult result = opcode.Evaluate(parameters, param_count, &context);
73    switch (result) {
74      case EVAL_FALSE:
75        evaluation = false;
76        if (kPolUseOREval != context.options) {
77          skip_group = true;
78        }
79        break;
80      case EVAL_ERROR:
81        if (kStopOnErrors & options) {
82          return POLICY_ERROR;
83        }
84        break;
85      case EVAL_TRUE:
86        evaluation = true;
87        if (kPolUseOREval == context.options) {
88          skip_group = true;
89        }
90        break;
91      default:
92        // We have evaluated an action.
93        SetInternalState(ix, result);
94        return POLICY_MATCH;
95    }
96  }
97
98  if (evaluation) {
99    // Reaching the end of the policy with a positive evaluation is probably
100    // an error: we did not find a final action opcode?
101    return POLICY_ERROR;
102  }
103  return NO_POLICY_MATCH;
104}
105
106
107}  // namespace sandbox
108