Add ICU message format support
[chromium-blink-merge.git] / sandbox / win / src / policy_engine_opcodes.h
blob17d1764b1c860185141fbf2ed1ca5c410b90f7c2
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 "base/basictypes.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "sandbox/win/src/policy_engine_params.h"
12 // The low-level policy is implemented using the concept of policy 'opcodes'.
13 // An opcode is a structure that contains enough information to perform one
14 // comparison against one single input parameter. For example, an opcode can
15 // encode just one of the following comparison:
17 // - Is input parameter 3 not equal to NULL?
18 // - Does input parameter 2 start with L"c:\\"?
19 // - Is input parameter 5, bit 3 is equal 1?
21 // Each opcode is in fact equivalent to a function invocation where all
22 // the parameters are known by the opcode except one. So say you have a
23 // function of this form:
24 // bool fn(a, b, c, d) with 4 arguments
26 // Then an opcode is:
27 // op(fn, b, c, d)
28 // Which stores the function to call and its 3 last arguments
30 // Then and opcode evaluation is:
31 // op.eval(a) ------------------------> fn(a,b,c,d)
32 // internally calls
34 // The idea is that complex policy rules can be split into streams of
35 // opcodes which are evaluated in sequence. The evaluation is done in
36 // groups of opcodes that have N comparison opcodes plus 1 action opcode:
38 // [comparison 1][comparison 2]...[comparison N][action][comparison 1]...
39 // ----- evaluation order----------->
41 // Each opcode group encodes one high-level policy rule. The rule applies
42 // only if all the conditions on the group evaluate to true. The action
43 // opcode contains the policy outcome for that particular rule.
45 // Note that this header contains the main building blocks of low-level policy
46 // but not the low level policy class.
47 namespace sandbox {
49 // These are the possible policy outcomes. Note that some of them might
50 // not apply and can be removed. Also note that The following values only
51 // specify what to do, not how to do it and it is acceptable given specific
52 // cases to ignore the policy outcome.
53 enum EvalResult {
54 // Comparison opcode values:
55 EVAL_TRUE, // Opcode condition evaluated true.
56 EVAL_FALSE, // Opcode condition evaluated false.
57 EVAL_ERROR, // Opcode condition generated an error while evaluating.
58 // Action opcode values:
59 ASK_BROKER, // The target must generate an IPC to the broker. On the broker
60 // side, this means grant access to the resource.
61 DENY_ACCESS, // No access granted to the resource.
62 GIVE_READONLY, // Give readonly access to the resource.
63 GIVE_ALLACCESS, // Give full access to the resource.
64 GIVE_CACHED, // IPC is not required. Target can return a cached handle.
65 GIVE_FIRST, // TODO(cpu)
66 SIGNAL_ALARM, // Unusual activity. Generate an alarm.
67 FAKE_SUCCESS, // Do not call original function. Just return 'success'.
68 FAKE_ACCESS_DENIED, // Do not call original function. Just return 'denied'
69 // and do not do IPC.
70 TERMINATE_PROCESS, // Destroy target process. Do IPC as well.
73 // The following are the implemented opcodes.
74 enum OpcodeID {
75 OP_ALWAYS_FALSE, // Evaluates to false (EVAL_FALSE).
76 OP_ALWAYS_TRUE, // Evaluates to true (EVAL_TRUE).
77 OP_NUMBER_MATCH, // Match a 32-bit integer as n == a.
78 OP_NUMBER_MATCH_RANGE, // Match a 32-bit integer as a <= n <= b.
79 OP_NUMBER_AND_MATCH, // Match using bitwise AND; as in: n & a != 0.
80 OP_WSTRING_MATCH, // Match a string for equality.
81 OP_ACTION // Evaluates to an action opcode.
84 // Options that apply to every opcode. They are specified when creating
85 // each opcode using OpcodeFactory::MakeOpXXXXX() family of functions
86 // Do nothing special.
87 const uint32 kPolNone = 0;
89 // Convert EVAL_TRUE into EVAL_FALSE and vice-versa. This allows to express
90 // negated conditions such as if ( a && !b).
91 const uint32 kPolNegateEval = 1;
93 // Zero the MatchContext context structure. This happens after the opcode
94 // is evaluated.
95 const uint32 kPolClearContext = 2;
97 // Use OR when evaluating this set of opcodes. The policy evaluator by default
98 // uses AND when evaluating. Very helpful when
99 // used with kPolNegateEval. For example if you have a condition best expressed
100 // as if(! (a && b && c)), the use of this flags allows it to be expressed as
101 // if ((!a) || (!b) || (!c)).
102 const uint32 kPolUseOREval = 4;
104 // Keeps the evaluation state between opcode evaluations. This is used
105 // for string matching where the next opcode needs to continue matching
106 // from the last character position from the current opcode. The match
107 // context is preserved across opcode evaluation unless an opcode specifies
108 // as an option kPolClearContext.
109 struct MatchContext {
110 size_t position;
111 uint32 options;
113 MatchContext() {
114 Clear();
117 void Clear() {
118 position = 0;
119 options = 0;
123 // Models a policy opcode; that is a condition evaluation were all the
124 // arguments but one are stored in objects of this class. Use OpcodeFactory
125 // to create objects of this type.
126 // This class is just an implementation artifact and not exposed to the
127 // API clients or visible in the intercepted service. Internally, an
128 // opcode is just:
129 // - An integer that identifies the actual opcode.
130 // - An index to indicate which one is the input argument
131 // - An array of arguments.
132 // While an OO hierarchy of objects would have been a natural choice, the fact
133 // that 1) this code can execute before the CRT is loaded, presents serious
134 // problems in terms of guarantees about the actual state of the vtables and
135 // 2) because the opcode objects are generated in the broker process, we need to
136 // use plain objects. To preserve some minimal type safety templates are used
137 // when possible.
138 class PolicyOpcode {
139 friend class OpcodeFactory;
140 public:
141 // Evaluates the opcode. For a typical comparison opcode the return value
142 // is EVAL_TRUE or EVAL_FALSE. If there was an error in the evaluation the
143 // the return is EVAL_ERROR. If the opcode is an action opcode then the
144 // return can take other values such as ASK_BROKER.
145 // parameters: An array of all input parameters. This argument is normally
146 // created by the macros POLPARAMS_BEGIN() POLPARAMS_END.
147 // count: The number of parameters passed as first argument.
148 // match: The match context that is persisted across the opcode evaluation
149 // sequence.
150 EvalResult Evaluate(const ParameterSet* parameters, size_t count,
151 MatchContext* match);
153 // Retrieves a stored argument by index. Valid index values are
154 // from 0 to < kArgumentCount.
155 template <typename T>
156 void GetArgument(size_t index, T* argument) const {
157 static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
158 *argument = *reinterpret_cast<const T*>(&arguments_[index].mem);
161 // Sets a stored argument by index. Valid index values are
162 // from 0 to < kArgumentCount.
163 template <typename T>
164 void SetArgument(size_t index, const T& argument) {
165 static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
166 *reinterpret_cast<T*>(&arguments_[index].mem) = argument;
169 // Retrieves the actual address of an string argument. When using
170 // GetArgument() to retrieve an index that contains a string, the returned
171 // value is just an offset to the actual string.
172 // index: the stored string index. Valid values are from 0
173 // to < kArgumentCount.
174 const wchar_t* GetRelativeString(size_t index) const {
175 ptrdiff_t str_delta = 0;
176 GetArgument(index, &str_delta);
177 const char* delta = reinterpret_cast<const char*>(this) + str_delta;
178 return reinterpret_cast<const wchar_t*>(delta);
181 // Returns true if this opcode is an action opcode without actually
182 // evaluating it. Used to do a quick scan forward to the next opcode group.
183 bool IsAction() const {
184 return (OP_ACTION == opcode_id_);
187 // Returns the opcode type.
188 OpcodeID GetID() const {
189 return opcode_id_;
192 // Returns the stored options such as kPolNegateEval and others.
193 uint32 GetOptions() const {
194 return options_;
197 // Sets the stored options such as kPolNegateEval.
198 void SetOptions(uint32 options) {
199 options_ = base::checked_cast<uint16>(options);
202 private:
204 static const size_t kArgumentCount = 4; // The number of supported argument.
206 struct OpcodeArgument {
207 UINT_PTR mem;
210 // Better define placement new in the class instead of relying on the
211 // global definition which seems to be fubared.
212 void* operator new(size_t, void* location) {
213 return location;
216 // Helper function to evaluate the opcode. The parameters have the same
217 // meaning that in Evaluate().
218 EvalResult EvaluateHelper(const ParameterSet* parameters,
219 MatchContext* match);
220 OpcodeID opcode_id_;
221 int16 parameter_;
222 // TODO(cpu): Making |options_| a uint32 would avoid casting, but causes test
223 // failures. Somewhere code is relying on the size of this struct.
224 // http://crbug.com/420296
225 uint16 options_;
226 OpcodeArgument arguments_[PolicyOpcode::kArgumentCount];
229 enum StringMatchOptions {
230 CASE_SENSITIVE = 0, // Pay or Not attention to the case as defined by
231 CASE_INSENSITIVE = 1, // RtlCompareUnicodeString windows API.
232 EXACT_LENGHT = 2 // Don't do substring match. Do full string match.
235 // Opcodes that do string comparisons take a parameter that is the starting
236 // position to perform the comparison so we can do substring matching. There
237 // are two special values:
239 // Start from the current position and compare strings advancing forward until
240 // a match is found if any. Similar to CRT strstr().
241 const int kSeekForward = -1;
242 // Perform a match with the end of the string. It only does a single comparison.
243 const int kSeekToEnd = 0xfffff;
246 // A PolicyBuffer is a variable size structure that contains all the opcodes
247 // that are to be created or evaluated in sequence.
248 struct PolicyBuffer {
249 size_t opcode_count;
250 PolicyOpcode opcodes[1];
253 // Helper class to create any opcode sequence. This class is normally invoked
254 // only by the high level policy module or when you need to handcraft a special
255 // policy.
256 // The factory works by creating the opcodes using a chunk of memory given
257 // in the constructor. The opcodes themselves are allocated from the beginning
258 // (top) of the memory, while any string that an opcode needs is allocated from
259 // the end (bottom) of the memory.
261 // In essence:
263 // low address ---> [opcode 1]
264 // [opcode 2]
265 // [opcode 3]
266 // | | <--- memory_top_
267 // | free |
268 // | |
269 // | | <--- memory_bottom_
270 // [string 1]
271 // high address --> [string 2]
273 // Note that this class does not keep track of the number of opcodes made and
274 // it is designed to be a building block for low-level policy.
276 // Note that any of the MakeOpXXXXX member functions below can return NULL on
277 // failure. When that happens opcode sequence creation must be aborted.
278 class OpcodeFactory {
279 public:
280 // memory: base pointer to a chunk of memory where the opcodes are created.
281 // memory_size: the size in bytes of the memory chunk.
282 OpcodeFactory(char* memory, size_t memory_size)
283 : memory_top_(memory) {
284 memory_bottom_ = &memory_top_[memory_size];
287 // policy: contains the raw memory where the opcodes are created.
288 // memory_size: contains the actual size of the policy argument.
289 OpcodeFactory(PolicyBuffer* policy, size_t memory_size) {
290 memory_top_ = reinterpret_cast<char*>(&policy->opcodes[0]);
291 memory_bottom_ = &memory_top_[memory_size];
294 // Returns the available memory to make opcodes.
295 size_t memory_size() const {
296 return memory_bottom_ - memory_top_;
299 // Creates an OpAlwaysFalse opcode.
300 PolicyOpcode* MakeOpAlwaysFalse(uint32 options);
302 // Creates an OpAlwaysFalse opcode.
303 PolicyOpcode* MakeOpAlwaysTrue(uint32 options);
305 // Creates an OpAction opcode.
306 // action: The action to return when Evaluate() is called.
307 PolicyOpcode* MakeOpAction(EvalResult action, uint32 options);
309 // Creates an OpNumberMatch opcode.
310 // selected_param: index of the input argument. It must be a uint32 or the
311 // evaluation result will generate a EVAL_ERROR.
312 // match: the number to compare against the selected_param.
313 PolicyOpcode* MakeOpNumberMatch(int16 selected_param,
314 uint32 match,
315 uint32 options);
317 // Creates an OpNumberMatch opcode (void pointers are cast to numbers).
318 // selected_param: index of the input argument. It must be an void* or the
319 // evaluation result will generate a EVAL_ERROR.
320 // match: the pointer numeric value to compare against selected_param.
321 PolicyOpcode* MakeOpVoidPtrMatch(int16 selected_param,
322 const void* match,
323 uint32 options);
325 // Creates an OpNumberMatchRange opcode using the memory passed in the ctor.
326 // selected_param: index of the input argument. It must be a uint32 or the
327 // evaluation result will generate a EVAL_ERROR.
328 // lower_bound, upper_bound: the range to compare against selected_param.
329 PolicyOpcode* MakeOpNumberMatchRange(int16 selected_param,
330 uint32 lower_bound,
331 uint32 upper_bound,
332 uint32 options);
334 // Creates an OpWStringMatch opcode using the raw memory passed in the ctor.
335 // selected_param: index of the input argument. It must be a wide string
336 // pointer or the evaluation result will generate a EVAL_ERROR.
337 // match_str: string to compare against selected_param.
338 // start_position: when its value is from 0 to < 0x7fff it indicates an
339 // offset from the selected_param string where to perform the comparison. If
340 // the value is SeekForward then a substring search is performed. If the
341 // value is SeekToEnd the comparison is performed against the last part of
342 // the selected_param string.
343 // Note that the range in the position (0 to 0x7fff) is dictated by the
344 // current implementation.
345 // match_opts: Indicates additional matching flags. Currently CaseInsensitive
346 // is supported.
347 PolicyOpcode* MakeOpWStringMatch(int16 selected_param,
348 const wchar_t* match_str,
349 int start_position,
350 StringMatchOptions match_opts,
351 uint32 options);
353 // Creates an OpNumberAndMatch opcode using the raw memory passed in the ctor.
354 // selected_param: index of the input argument. It must be uint32 or the
355 // evaluation result will generate a EVAL_ERROR.
356 // match: the value to bitwise AND against selected_param.
357 PolicyOpcode* MakeOpNumberAndMatch(int16 selected_param,
358 uint32 match,
359 uint32 options);
361 private:
362 // Constructs the common part of every opcode. selected_param is the index
363 // of the input param to use when evaluating the opcode. Pass -1 in
364 // selected_param to indicate that no input parameter is required.
365 PolicyOpcode* MakeBase(OpcodeID opcode_id, uint32 options,
366 int16 selected_param);
368 // Allocates (and copies) a string (of size length) inside the buffer and
369 // returns the displacement with respect to start.
370 ptrdiff_t AllocRelative(void* start, const wchar_t* str, size_t lenght);
372 // Points to the lowest currently available address of the memory
373 // used to make the opcodes. This pointer increments as opcodes are made.
374 char* memory_top_;
376 // Points to the highest currently available address of the memory
377 // used to make the opcodes. This pointer decrements as opcode strings are
378 // allocated.
379 char* memory_bottom_;
381 DISALLOW_COPY_AND_ASSIGN(OpcodeFactory);
384 } // namespace sandbox
386 #endif // SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_