summaryrefslogtreecommitdiff
path: root/sandbox/win/src/policy_engine_processor.h
blob: 9e416bd35fcb0860e8f2b3127ee4824c406847a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2010 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.

#ifndef SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
#define SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__

#include "base/basictypes.h"
#include "sandbox/win/src/policy_engine_params.h"
#include "sandbox/win/src/policy_engine_opcodes.h"

namespace sandbox {

// This header contains the core policy evaluator. In its simplest form
// it evaluates a stream of opcodes assuming that they are laid out in
// memory as opcode groups.
//
// An opcode group has N comparison opcodes plus 1 action opcode. For
// example here we have 3 opcode groups (A, B,C):
//
// [comparison 1]  <-- group A start
// [comparison 2]
// [comparison 3]
// [action A    ]
// [comparison 1]  <-- group B start
// [action B    ]
// [comparison 1]  <-- group C start
// [comparison 2]
// [action C    ]
//
// The opcode evaluator proceeds from the top, evaluating each opcode in
// sequence. An opcode group is evaluated until the first comparison that
// returns false. At that point the rest of the group is skipped and evaluation
// resumes with the first comparison of the next group. When all the comparisons
// in a group have evaluated to true and the action is reached. The group is
// considered a matching group.
//
// In the 'ShortEval' mode evaluation stops when it reaches the end or the first
// matching group. The action opcode from this group is the resulting policy
// action.
//
// In the 'RankedEval' mode evaluation stops only when it reaches the end of the
// the opcode stream. In the process all matching groups are saved and at the
// end the 'best' group is selected (what makes the best is TBD) and the action
// from this group is the resulting policy action.
//
// As explained above, the policy evaluation of a group is a logical AND of
// the evaluation of each opcode. However an opcode can request kPolUseOREval
// which makes the evaluation to use logical OR. Given that each opcode can
// request its evaluation result to be negated with kPolNegateEval you can
// achieve the negation of the total group evaluation. This means that if you
// need to express:
//             if (!(c1 && c2 && c3))
// You can do it by:
//             if ((!c1) || (!c2) || (!c3))
//

// Possible outcomes of policy evaluation.
enum PolicyResult {
  NO_POLICY_MATCH,
  POLICY_MATCH,
  POLICY_ERROR
};

// Policy evaluation flags
// TODO(cpu): implement the options kStopOnErrors & kRankedEval.
//
// Stop evaluating as soon as an error is encountered.
const uint32 kStopOnErrors = 1;
// Ignore all non fatal opcode evaluation errors.
const uint32 kIgnoreErrors = 2;
// Short-circuit evaluation: Only evaluate until opcode group that
// evaluated to true has been found.
const uint32 kShortEval = 4;
// Discussed briefly at the policy design meeting. It will evaluate
// all rules and then return the 'best' rule that evaluated true.
const uint32 kRankedEval = 8;

// This class evaluates a policy-opcode stream given the memory where the
// opcodes are and an input 'parameter set'.
//
// This class is designed to be callable from interception points
// as low as the NtXXXX service level (it is not currently safe, but
// it is designed to be made safe).
//
// Its usage in an interception is:
//
//   POLPARAMS_BEGIN(eval_params)
//     POLPARAM(param1)
//     POLPARAM(param2)
//     POLPARAM(param3)
//     POLPARAM(param4)
//     POLPARAM(param5)
//   POLPARAMS_END;
//
//   PolicyProcessor pol_evaluator(policy_memory);
//   PolicyResult pr = pol_evaluator.Evaluate(ShortEval, eval_params,
//                                            _countof(eval_params));
//   if (NO_POLICY_MATCH == pr) {
//     EvalResult policy_action =  pol_evaluator.GetAction();
//     // apply policy here...
//   }
//
// Where the POLPARAM() arguments are derived from the intercepted function
// arguments, and represent all the 'interesting' policy inputs, and
// policy_memory is a memory buffer containing the opcode stream that is the
// relevant policy for this intercept.
class PolicyProcessor {
 public:
  // policy_buffer contains opcodes made with OpcodeFactory. They are usually
  // created in the broker process and evaluated in the target process.

  // This constructor is just a variant of the previous constructor.
  explicit PolicyProcessor(PolicyBuffer* policy)
      : policy_(policy) {
    SetInternalState(0, EVAL_FALSE);
  }

  // Evaluates a policy-opcode stream. See the comments at the top of this
  // class for more info. Returns POLICY_MATCH if a rule set was found that
  // matches an active policy.
  PolicyResult Evaluate(uint32 options,
                        ParameterSet* parameters,
                        size_t parameter_count);

  // If the result of Evaluate() was POLICY_MATCH, calling this function returns
  // the recommended policy action.
  EvalResult GetAction() const;

 private:
  struct {
    size_t current_index_;
    EvalResult current_result_;
  } state_;

  // Sets the currently matching action result.
  void SetInternalState(size_t index, EvalResult result);

  PolicyBuffer* policy_;
  DISALLOW_COPY_AND_ASSIGN(PolicyProcessor);
};

}  // namespace sandbox

#endif  // SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__