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