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.
5 #ifndef SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
6 #define SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
8 #include "sandbox/win/src/policy_engine_params.h"
9 #include "base/basictypes.h"
11 // The low-level policy is implemented using the concept of policy 'opcodes'.
12 // An opcode is a structure that contains enough information to perform one
13 // comparison against one single input parameter. For example, an opcode can
14 // encode just one of the following comparison:
16 // - Is input parameter 3 not equal to NULL?
17 // - Does input parameter 2 start with L"c:\\"?
18 // - Is input parameter 5, bit 3 is equal 1?
20 // Each opcode is in fact equivalent to a function invocation where all
21 // the parameters are known by the opcode except one. So say you have a
22 // function of this form:
23 // bool fn(a, b, c, d) with 4 arguments
27 // Which stores the function to call and its 3 last arguments
29 // Then and opcode evaluation is:
30 // op.eval(a) ------------------------> fn(a,b,c,d)
33 // The idea is that complex policy rules can be split into streams of
34 // opcodes which are evaluated in sequence. The evaluation is done in
35 // groups of opcodes that have N comparison opcodes plus 1 action opcode:
37 // [comparison 1][comparison 2]...[comparison N][action][comparison 1]...
38 // ----- evaluation order----------->
40 // Each opcode group encodes one high-level policy rule. The rule applies
41 // only if all the conditions on the group evaluate to true. The action
42 // opcode contains the policy outcome for that particular rule.
44 // Note that this header contains the main building blocks of low-level policy
45 // but not the low level policy class.
48 // These are the possible policy outcomes. Note that some of them might
49 // not apply and can be removed. Also note that The following values only
50 // specify what to do, not how to do it and it is acceptable given specific
51 // cases to ignore the policy outcome.
53 // Comparison opcode values:
54 EVAL_TRUE
, // Opcode condition evaluated true.
55 EVAL_FALSE
, // Opcode condition evaluated false.
56 EVAL_ERROR
, // Opcode condition generated an error while evaluating.
57 // Action opcode values:
58 ASK_BROKER
, // The target must generate an IPC to the broker. On the broker
59 // side, this means grant access to the resource.
60 DENY_ACCESS
, // No access granted to the resource.
61 GIVE_READONLY
, // Give readonly access to the resource.
62 GIVE_ALLACCESS
, // Give full access to the resource.
63 GIVE_CACHED
, // IPC is not required. Target can return a cached handle.
64 GIVE_FIRST
, // TODO(cpu)
65 SIGNAL_ALARM
, // Unusual activity. Generate an alarm.
66 FAKE_SUCCESS
, // Do not call original function. Just return 'success'.
67 FAKE_ACCESS_DENIED
, // Do not call original function. Just return 'denied'
69 TERMINATE_PROCESS
, // Destroy target process. Do IPC as well.
72 // The following are the implemented opcodes.
74 OP_ALWAYS_FALSE
, // Evaluates to false (EVAL_FALSE).
75 OP_ALWAYS_TRUE
, // Evaluates to true (EVAL_TRUE).
76 OP_NUMBER_MATCH
, // Match a 32-bit integer as n == a.
77 OP_ULONG_MATCH_RANGE
, // Match an ulong integer as a <= n <= b.
78 OP_ULONG_AND_MATCH
, // Match using bitwise AND; as in: n & a != 0.
79 OP_WSTRING_MATCH
, // Match a string for equality.
80 OP_ACTION
// Evaluates to an action opcode.
83 // Options that apply to every opcode. They are specified when creating
84 // each opcode using OpcodeFactory::MakeOpXXXXX() family of functions
85 // Do nothing special.
86 const uint32 kPolNone
= 0;
88 // Convert EVAL_TRUE into EVAL_FALSE and vice-versa. This allows to express
89 // negated conditions such as if ( a && !b).
90 const uint32 kPolNegateEval
= 1;
92 // Zero the MatchContext context structure. This happens after the opcode
94 const uint32 kPolClearContext
= 2;
96 // Use OR when evaluating this set of opcodes. The policy evaluator by default
97 // uses AND when evaluating. Very helpful when
98 // used with kPolNegateEval. For example if you have a condition best expressed
99 // as if(! (a && b && c)), the use of this flags allows it to be expressed as
100 // if ((!a) || (!b) || (!c)).
101 const uint32 kPolUseOREval
= 4;
103 // Keeps the evaluation state between opcode evaluations. This is used
104 // for string matching where the next opcode needs to continue matching
105 // from the last character position from the current opcode. The match
106 // context is preserved across opcode evaluation unless an opcode specifies
107 // as an option kPolClearContext.
108 struct MatchContext
{
122 // Models a policy opcode; that is a condition evaluation were all the
123 // arguments but one are stored in objects of this class. Use OpcodeFactory
124 // to create objects of this type.
125 // This class is just an implementation artifact and not exposed to the
126 // API clients or visible in the intercepted service. Internally, an
128 // - An integer that identifies the actual opcode.
129 // - An index to indicate which one is the input argument
130 // - An array of arguments.
131 // While an OO hierarchy of objects would have been a natural choice, the fact
132 // that 1) this code can execute before the CRT is loaded, presents serious
133 // problems in terms of guarantees about the actual state of the vtables and
134 // 2) because the opcode objects are generated in the broker process, we need to
135 // use plain objects. To preserve some minimal type safety templates are used
138 friend class OpcodeFactory
;
140 // Evaluates the opcode. For a typical comparison opcode the return value
141 // is EVAL_TRUE or EVAL_FALSE. If there was an error in the evaluation the
142 // the return is EVAL_ERROR. If the opcode is an action opcode then the
143 // return can take other values such as ASK_BROKER.
144 // parameters: An array of all input parameters. This argument is normally
145 // created by the macros POLPARAMS_BEGIN() POLPARAMS_END.
146 // count: The number of parameters passed as first argument.
147 // match: The match context that is persisted across the opcode evaluation
149 EvalResult
Evaluate(const ParameterSet
* parameters
, size_t count
,
150 MatchContext
* match
);
152 // Retrieves a stored argument by index. Valid index values are
153 // from 0 to < kArgumentCount.
154 template <typename T
>
155 void GetArgument(size_t index
, T
* argument
) const {
156 COMPILE_ASSERT(sizeof(T
) <= sizeof(arguments_
[0]), invalid_size
);
157 *argument
= *reinterpret_cast<const T
*>(&arguments_
[index
].mem
);
160 // Sets a stored argument by index. Valid index values are
161 // from 0 to < kArgumentCount.
162 template <typename T
>
163 void SetArgument(size_t index
, const T
& argument
) {
164 COMPILE_ASSERT(sizeof(T
) <= sizeof(arguments_
[0]), invalid_size
);
165 *reinterpret_cast<T
*>(&arguments_
[index
].mem
) = argument
;
168 // Retrieves the actual address of an string argument. When using
169 // GetArgument() to retrieve an index that contains a string, the returned
170 // value is just an offset to the actual string.
171 // index: the stored string index. Valid values are from 0
172 // to < kArgumentCount.
173 const wchar_t* GetRelativeString(size_t index
) const {
174 ptrdiff_t str_delta
= 0;
175 GetArgument(index
, &str_delta
);
176 const char* delta
= reinterpret_cast<const char*>(this) + str_delta
;
177 return reinterpret_cast<const wchar_t*>(delta
);
180 // Returns true if this opcode is an action opcode without actually
181 // evaluating it. Used to do a quick scan forward to the next opcode group.
182 bool IsAction() const {
183 return (OP_ACTION
== opcode_id_
);
186 // Returns the opcode type.
187 OpcodeID
GetID() const {
191 // Returns the stored options such as kPolNegateEval and others.
192 uint32
GetOptions() const {
196 // Sets the stored options such as kPolNegateEval.
197 void SetOptions(int16 options
) {
203 static const size_t kArgumentCount
= 4; // The number of supported argument.
205 struct OpcodeArgument
{
209 // Better define placement new in the class instead of relying on the
210 // global definition which seems to be fubared.
211 void* operator new(size_t, void* location
) {
215 // Helper function to evaluate the opcode. The parameters have the same
216 // meaning that in Evaluate().
217 EvalResult
EvaluateHelper(const ParameterSet
* parameters
,
218 MatchContext
* match
);
222 OpcodeArgument arguments_
[PolicyOpcode::kArgumentCount
];
225 enum StringMatchOptions
{
226 CASE_SENSITIVE
= 0, // Pay or Not attention to the case as defined by
227 CASE_INSENSITIVE
= 1, // RtlCompareUnicodeString windows API.
228 EXACT_LENGHT
= 2 // Don't do substring match. Do full string match.
231 // Opcodes that do string comparisons take a parameter that is the starting
232 // position to perform the comparison so we can do substring matching. There
233 // are two special values:
235 // Start from the current position and compare strings advancing forward until
236 // a match is found if any. Similar to CRT strstr().
237 const int kSeekForward
= -1;
238 // Perform a match with the end of the string. It only does a single comparison.
239 const int kSeekToEnd
= 0xfffff;
242 // A PolicyBuffer is a variable size structure that contains all the opcodes
243 // that are to be created or evaluated in sequence.
244 struct PolicyBuffer
{
246 PolicyOpcode opcodes
[1];
249 // Helper class to create any opcode sequence. This class is normally invoked
250 // only by the high level policy module or when you need to handcraft a special
252 // The factory works by creating the opcodes using a chunk of memory given
253 // in the constructor. The opcodes themselves are allocated from the beginning
254 // (top) of the memory, while any string that an opcode needs is allocated from
255 // the end (bottom) of the memory.
259 // low address ---> [opcode 1]
262 // | | <--- memory_top_
265 // | | <--- memory_bottom_
267 // high address --> [string 2]
269 // Note that this class does not keep track of the number of opcodes made and
270 // it is designed to be a building block for low-level policy.
272 // Note that any of the MakeOpXXXXX member functions below can return NULL on
273 // failure. When that happens opcode sequence creation must be aborted.
274 class OpcodeFactory
{
276 // memory: base pointer to a chunk of memory where the opcodes are created.
277 // memory_size: the size in bytes of the memory chunk.
278 OpcodeFactory(char* memory
, size_t memory_size
)
279 : memory_top_(memory
) {
280 memory_bottom_
= &memory_top_
[memory_size
];
283 // policy: contains the raw memory where the opcodes are created.
284 // memory_size: contains the actual size of the policy argument.
285 OpcodeFactory(PolicyBuffer
* policy
, size_t memory_size
) {
286 memory_top_
= reinterpret_cast<char*>(&policy
->opcodes
[0]);
287 memory_bottom_
= &memory_top_
[memory_size
];
290 // Returns the available memory to make opcodes.
291 size_t memory_size() const {
292 return memory_bottom_
- memory_top_
;
295 // Creates an OpAlwaysFalse opcode.
296 PolicyOpcode
* MakeOpAlwaysFalse(uint32 options
);
298 // Creates an OpAlwaysFalse opcode.
299 PolicyOpcode
* MakeOpAlwaysTrue(uint32 options
);
301 // Creates an OpAction opcode.
302 // action: The action to return when Evaluate() is called.
303 PolicyOpcode
* MakeOpAction(EvalResult action
, uint32 options
);
305 // Creates an OpNumberMatch opcode.
306 // selected_param: index of the input argument. It must be a ulong or the
307 // evaluation result will generate a EVAL_ERROR.
308 // match: the number to compare against the selected_param.
309 PolicyOpcode
* MakeOpNumberMatch(int16 selected_param
, unsigned long match
,
312 // Creates an OpNumberMatch opcode (void pointers are cast to numbers).
313 // selected_param: index of the input argument. It must be an void* or the
314 // evaluation result will generate a EVAL_ERROR.
315 // match: the pointer numeric value to compare against selected_param.
316 PolicyOpcode
* MakeOpVoidPtrMatch(int16 selected_param
, const void* match
,
319 // Creates an OpUlongMatchRange opcode using the memory passed in the ctor.
320 // selected_param: index of the input argument. It must be a ulong or the
321 // evaluation result will generate a EVAL_ERROR.
322 // lower_bound, upper_bound: the range to compare against selected_param.
323 PolicyOpcode
* MakeOpUlongMatchRange(int16 selected_param
,
324 unsigned long lower_bound
,
325 unsigned long upper_bound
,
328 // Creates an OpWStringMatch opcode using the raw memory passed in the ctor.
329 // selected_param: index of the input argument. It must be a wide string
330 // pointer or the evaluation result will generate a EVAL_ERROR.
331 // match_str: string to compare against selected_param.
332 // start_position: when its value is from 0 to < 0x7fff it indicates an
333 // offset from the selected_param string where to perform the comparison. If
334 // the value is SeekForward then a substring search is performed. If the
335 // value is SeekToEnd the comparison is performed against the last part of
336 // the selected_param string.
337 // Note that the range in the position (0 to 0x7fff) is dictated by the
338 // current implementation.
339 // match_opts: Indicates additional matching flags. Currently CaseInsensitive
341 PolicyOpcode
* MakeOpWStringMatch(int16 selected_param
,
342 const wchar_t* match_str
,
344 StringMatchOptions match_opts
,
347 // Creates an OpUlongAndMatch opcode using the raw memory passed in the ctor.
348 // selected_param: index of the input argument. It must be ulong or the
349 // evaluation result will generate a EVAL_ERROR.
350 // match: the value to bitwise AND against selected_param.
351 PolicyOpcode
* MakeOpUlongAndMatch(int16 selected_param
,
356 // Constructs the common part of every opcode. selected_param is the index
357 // of the input param to use when evaluating the opcode. Pass -1 in
358 // selected_param to indicate that no input parameter is required.
359 PolicyOpcode
* MakeBase(OpcodeID opcode_id
, uint32 options
,
360 int16 selected_param
);
362 // Allocates (and copies) a string (of size length) inside the buffer and
363 // returns the displacement with respect to start.
364 ptrdiff_t AllocRelative(void* start
, const wchar_t* str
, size_t lenght
);
366 // Points to the lowest currently available address of the memory
367 // used to make the opcodes. This pointer increments as opcodes are made.
370 // Points to the highest currently available address of the memory
371 // used to make the opcodes. This pointer decrements as opcode strings are
373 char* memory_bottom_
;
375 DISALLOW_COPY_AND_ASSIGN(OpcodeFactory
);
378 } // namespace sandbox
380 #endif // SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_