1 // Copyright (c) 2010 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 #ifndef SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
6 #define SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include "base/macros.h"
12 #include "sandbox/win/src/policy_engine_opcodes.h"
13 #include "sandbox/win/src/policy_engine_params.h"
14 
15 namespace sandbox {
16 
17 // This header contains the core policy evaluator. In its simplest form
18 // it evaluates a stream of opcodes assuming that they are laid out in
19 // memory as opcode groups.
20 //
21 // An opcode group has N comparison opcodes plus 1 action opcode. For
22 // example here we have 3 opcode groups (A, B,C):
23 //
24 // [comparison 1]  <-- group A start
25 // [comparison 2]
26 // [comparison 3]
27 // [action A    ]
28 // [comparison 1]  <-- group B start
29 // [action B    ]
30 // [comparison 1]  <-- group C start
31 // [comparison 2]
32 // [action C    ]
33 //
34 // The opcode evaluator proceeds from the top, evaluating each opcode in
35 // sequence. An opcode group is evaluated until the first comparison that
36 // returns false. At that point the rest of the group is skipped and evaluation
37 // resumes with the first comparison of the next group. When all the comparisons
38 // in a group have evaluated to true and the action is reached. The group is
39 // considered a matching group.
40 //
41 // In the 'ShortEval' mode evaluation stops when it reaches the end or the first
42 // matching group. The action opcode from this group is the resulting policy
43 // action.
44 //
45 // In the 'RankedEval' mode evaluation stops only when it reaches the end of the
46 // the opcode stream. In the process all matching groups are saved and at the
47 // end the 'best' group is selected (what makes the best is TBD) and the action
48 // from this group is the resulting policy action.
49 //
50 // As explained above, the policy evaluation of a group is a logical AND of
51 // the evaluation of each opcode. However an opcode can request kPolUseOREval
52 // which makes the evaluation to use logical OR. Given that each opcode can
53 // request its evaluation result to be negated with kPolNegateEval you can
54 // achieve the negation of the total group evaluation. This means that if you
55 // need to express:
56 //             if (!(c1 && c2 && c3))
57 // You can do it by:
58 //             if ((!c1) || (!c2) || (!c3))
59 //
60 
61 // Possible outcomes of policy evaluation.
62 enum PolicyResult { NO_POLICY_MATCH, POLICY_MATCH, POLICY_ERROR };
63 
64 // Policy evaluation flags
65 // TODO(cpu): implement the options kStopOnErrors & kRankedEval.
66 //
67 // Stop evaluating as soon as an error is encountered.
68 const uint32_t kStopOnErrors = 1;
69 // Ignore all non fatal opcode evaluation errors.
70 const uint32_t kIgnoreErrors = 2;
71 // Short-circuit evaluation: Only evaluate until opcode group that
72 // evaluated to true has been found.
73 const uint32_t kShortEval = 4;
74 // Discussed briefly at the policy design meeting. It will evaluate
75 // all rules and then return the 'best' rule that evaluated true.
76 const uint32_t kRankedEval = 8;
77 
78 // This class evaluates a policy-opcode stream given the memory where the
79 // opcodes are and an input 'parameter set'.
80 //
81 // This class is designed to be callable from interception points
82 // as low as the NtXXXX service level (it is not currently safe, but
83 // it is designed to be made safe).
84 //
85 // Its usage in an interception is:
86 //
87 //   POLPARAMS_BEGIN(eval_params)
88 //     POLPARAM(param1)
89 //     POLPARAM(param2)
90 //     POLPARAM(param3)
91 //     POLPARAM(param4)
92 //     POLPARAM(param5)
93 //   POLPARAMS_END;
94 //
95 //   PolicyProcessor pol_evaluator(policy_memory);
96 //   PolicyResult pr = pol_evaluator.Evaluate(ShortEval, eval_params,
97 //                                            _countof(eval_params));
98 //   if (NO_POLICY_MATCH == pr) {
99 //     EvalResult policy_action =  pol_evaluator.GetAction();
100 //     // apply policy here...
101 //   }
102 //
103 // Where the POLPARAM() arguments are derived from the intercepted function
104 // arguments, and represent all the 'interesting' policy inputs, and
105 // policy_memory is a memory buffer containing the opcode stream that is the
106 // relevant policy for this intercept.
107 class PolicyProcessor {
108  public:
109   // policy_buffer contains opcodes made with OpcodeFactory. They are usually
110   // created in the broker process and evaluated in the target process.
111 
112   // This constructor is just a variant of the previous constructor.
PolicyProcessor(PolicyBuffer * policy)113   explicit PolicyProcessor(PolicyBuffer* policy) : policy_(policy) {
114     SetInternalState(0, EVAL_FALSE);
115   }
116 
117   // Evaluates a policy-opcode stream. See the comments at the top of this
118   // class for more info. Returns POLICY_MATCH if a rule set was found that
119   // matches an active policy.
120   PolicyResult Evaluate(uint32_t options,
121                         ParameterSet* parameters,
122                         size_t parameter_count);
123 
124   // If the result of Evaluate() was POLICY_MATCH, calling this function returns
125   // the recommended policy action.
126   EvalResult GetAction() const;
127 
128  private:
129   struct {
130     size_t current_index_;
131     EvalResult current_result_;
132   } state_;
133 
134   // Sets the currently matching action result.
135   void SetInternalState(size_t index, EvalResult result);
136 
137   PolicyBuffer* policy_;
138   DISALLOW_COPY_AND_ASSIGN(PolicyProcessor);
139 };
140 
141 }  // namespace sandbox
142 
143 #endif  // SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
144