|
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 |
|
7 namespace sandbox { |
|
8 |
|
9 void PolicyProcessor::SetInternalState(size_t index, EvalResult result) { |
|
10 state_.current_index_ = index; |
|
11 state_.current_result_ = result; |
|
12 } |
|
13 |
|
14 EvalResult 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. |
|
23 bool 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 |
|
35 PolicyResult 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 |