15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_ 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/policy_engine_params.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The low-level policy is implemented using the concept of policy 'opcodes'. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An opcode is a structure that contains enough information to perform one 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// comparison against one single input parameter. For example, an opcode can 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// encode just one of the following comparison: 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Is input parameter 3 not equal to NULL? 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Does input parameter 2 start with L"c:\\"? 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Is input parameter 5, bit 3 is equal 1? 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each opcode is in fact equivalent to a function invocation where all 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the parameters are known by the opcode except one. So say you have a 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function of this form: 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// bool fn(a, b, c, d) with 4 arguments 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Then an opcode is: 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// op(fn, b, c, d) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Which stores the function to call and its 3 last arguments 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Then and opcode evaluation is: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// op.eval(a) ------------------------> fn(a,b,c,d) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// internally calls 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The idea is that complex policy rules can be split into streams of 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opcodes which are evaluated in sequence. The evaluation is done in 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// groups of opcodes that have N comparison opcodes plus 1 action opcode: 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [comparison 1][comparison 2]...[comparison N][action][comparison 1]... 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----- evaluation order-----------> 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each opcode group encodes one high-level policy rule. The rule applies 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only if all the conditions on the group evaluate to true. The action 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opcode contains the policy outcome for that particular rule. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this header contains the main building blocks of low-level policy 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but not the low level policy class. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sandbox { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These are the possible policy outcomes. Note that some of them might 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not apply and can be removed. Also note that The following values only 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specify what to do, not how to do it and it is acceptable given specific 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cases to ignore the policy outcome. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum EvalResult { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Comparison opcode values: 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVAL_TRUE, // Opcode condition evaluated true. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVAL_FALSE, // Opcode condition evaluated false. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVAL_ERROR, // Opcode condition generated an error while evaluating. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Action opcode values: 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASK_BROKER, // The target must generate an IPC to the broker. On the broker 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // side, this means grant access to the resource. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DENY_ACCESS, // No access granted to the resource. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GIVE_READONLY, // Give readonly access to the resource. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GIVE_ALLACCESS, // Give full access to the resource. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GIVE_CACHED, // IPC is not required. Target can return a cached handle. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GIVE_FIRST, // TODO(cpu) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIGNAL_ALARM, // Unusual activity. Generate an alarm. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAKE_SUCCESS, // Do not call original function. Just return 'success'. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAKE_ACCESS_DENIED, // Do not call original function. Just return 'denied' 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and do not do IPC. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TERMINATE_PROCESS, // Destroy target process. Do IPC as well. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following are the implemented opcodes. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum OpcodeID { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_ALWAYS_FALSE, // Evaluates to false (EVAL_FALSE). 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_ALWAYS_TRUE, // Evaluates to true (EVAL_TRUE). 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_NUMBER_MATCH, // Match a 32-bit integer as n == a. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_ULONG_MATCH_RANGE, // Match an ulong integer as a <= n <= b. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_ULONG_AND_MATCH, // Match using bitwise AND; as in: n & a != 0. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_WSTRING_MATCH, // Match a string for equality. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OP_ACTION // Evaluates to an action opcode. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Options that apply to every opcode. They are specified when creating 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each opcode using OpcodeFactory::MakeOpXXXXX() family of functions 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Do nothing special. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kPolNone = 0; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Convert EVAL_TRUE into EVAL_FALSE and vice-versa. This allows to express 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// negated conditions such as if ( a && !b). 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kPolNegateEval = 1; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Zero the MatchContext context structure. This happens after the opcode 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is evaluated. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kPolClearContext = 2; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use OR when evaluating this set of opcodes. The policy evaluator by default 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// uses AND when evaluating. Very helpful when 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used with kPolNegateEval. For example if you have a condition best expressed 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// as if(! (a && b && c)), the use of this flags allows it to be expressed as 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if ((!a) || (!b) || (!c)). 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kPolUseOREval = 4; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Keeps the evaluation state between opcode evaluations. This is used 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for string matching where the next opcode needs to continue matching 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the last character position from the current opcode. The match 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// context is preserved across opcode evaluation unless an opcode specifies 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// as an option kPolClearContext. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct MatchContext { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t position; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MatchContext() { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Clear(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Clear() { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) position = 0; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options = 0; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Models a policy opcode; that is a condition evaluation were all the 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// arguments but one are stored in objects of this class. Use OpcodeFactory 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to create objects of this type. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is just an implementation artifact and not exposed to the 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// API clients or visible in the intercepted service. Internally, an 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opcode is just: 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - An integer that identifies the actual opcode. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - An index to indicate which one is the input argument 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - An array of arguments. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// While an OO hierarchy of objects would have been a natural choice, the fact 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that 1) this code can execute before the CRT is loaded, presents serious 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// problems in terms of guarantees about the actual state of the vtables and 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2) because the opcode objects are generated in the broker process, we need to 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use plain objects. To preserve some minimal type safety templates are used 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when possible. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PolicyOpcode { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class OpcodeFactory; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Evaluates the opcode. For a typical comparison opcode the return value 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is EVAL_TRUE or EVAL_FALSE. If there was an error in the evaluation the 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the return is EVAL_ERROR. If the opcode is an action opcode then the 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return can take other values such as ASK_BROKER. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parameters: An array of all input parameters. This argument is normally 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // created by the macros POLPARAMS_BEGIN() POLPARAMS_END. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // count: The number of parameters passed as first argument. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match: The match context that is persisted across the opcode evaluation 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sequence. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EvalResult Evaluate(const ParameterSet* parameters, size_t count, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MatchContext* match); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Retrieves a stored argument by index. Valid index values are 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from 0 to < kArgumentCount. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <typename T> 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void GetArgument(size_t index, T* argument) const { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(sizeof(T) <= sizeof(arguments_[0]), invalid_size); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *argument = *reinterpret_cast<const T*>(&arguments_[index].mem); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets a stored argument by index. Valid index values are 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from 0 to < kArgumentCount. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) template <typename T> 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetArgument(size_t index, const T& argument) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(sizeof(T) <= sizeof(arguments_[0]), invalid_size); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<T*>(&arguments_[index].mem) = argument; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Retrieves the actual address of an string argument. When using 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetArgument() to retrieve an index that contains a string, the returned 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value is just an offset to the actual string. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // index: the stored string index. Valid values are from 0 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to < kArgumentCount. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const wchar_t* GetRelativeString(size_t index) const { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptrdiff_t str_delta = 0; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetArgument(index, &str_delta); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* delta = reinterpret_cast<const char*>(this) + str_delta; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reinterpret_cast<const wchar_t*>(delta); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if this opcode is an action opcode without actually 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // evaluating it. Used to do a quick scan forward to the next opcode group. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsAction() const { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (OP_ACTION == opcode_id_); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the opcode type. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpcodeID GetID() const { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return opcode_id_; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the stored options such as kPolNegateEval and others. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 GetOptions() const { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return options_; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets the stored options such as kPolNegateEval. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetOptions(int16 options) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options_ = options; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const size_t kArgumentCount = 4; // The number of supported argument. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct OpcodeArgument { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT_PTR mem; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Better define placement new in the class instead of relying on the 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // global definition which seems to be fubared. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* operator new(size_t, void* location) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return location; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Helper function to evaluate the opcode. The parameters have the same 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // meaning that in Evaluate(). 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EvalResult EvaluateHelper(const ParameterSet* parameters, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MatchContext* match); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpcodeID opcode_id_; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int16 parameter_; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int16 options_; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpcodeArgument arguments_[PolicyOpcode::kArgumentCount]; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum StringMatchOptions { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CASE_SENSITIVE = 0, // Pay or Not attention to the case as defined by 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CASE_INSENSITIVE = 1, // RtlCompareUnicodeString windows API. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXACT_LENGHT = 2 // Don't do substring match. Do full string match. 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Opcodes that do string comparisons take a parameter that is the starting 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// position to perform the comparison so we can do substring matching. There 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are two special values: 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Start from the current position and compare strings advancing forward until 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a match is found if any. Similar to CRT strstr(). 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSeekForward = -1; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Perform a match with the end of the string. It only does a single comparison. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSeekToEnd = 0xfffff; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PolicyBuffer is a variable size structure that contains all the opcodes 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that are to be created or evaluated in sequence. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PolicyBuffer { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t opcode_count; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode opcodes[1]; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class to create any opcode sequence. This class is normally invoked 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only by the high level policy module or when you need to handcraft a special 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// policy. 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The factory works by creating the opcodes using a chunk of memory given 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the constructor. The opcodes themselves are allocated from the beginning 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (top) of the memory, while any string that an opcode needs is allocated from 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the end (bottom) of the memory. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In essence: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// low address ---> [opcode 1] 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [opcode 2] 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [opcode 3] 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | | <--- memory_top_ 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | free | 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | | 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | | <--- memory_bottom_ 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [string 1] 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// high address --> [string 2] 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this class does not keep track of the number of opcodes made and 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it is designed to be a building block for low-level policy. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that any of the MakeOpXXXXX member functions below can return NULL on 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// failure. When that happens opcode sequence creation must be aborted. 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OpcodeFactory { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memory: base pointer to a chunk of memory where the opcodes are created. 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memory_size: the size in bytes of the memory chunk. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpcodeFactory(char* memory, size_t memory_size) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : memory_top_(memory) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_bottom_ = &memory_top_[memory_size]; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // policy: contains the raw memory where the opcodes are created. 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memory_size: contains the actual size of the policy argument. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OpcodeFactory(PolicyBuffer* policy, size_t memory_size) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_top_ = reinterpret_cast<char*>(&policy->opcodes[0]); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_bottom_ = &memory_top_[memory_size]; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns the available memory to make opcodes. 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t memory_size() const { 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return memory_bottom_ - memory_top_; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpAlwaysFalse opcode. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpAlwaysFalse(uint32 options); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpAlwaysFalse opcode. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpAlwaysTrue(uint32 options); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpAction opcode. 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // action: The action to return when Evaluate() is called. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpAction(EvalResult action, uint32 options); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpNumberMatch opcode. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param: index of the input argument. It must be a ulong or the 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // evaluation result will generate a EVAL_ERROR. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match: the number to compare against the selected_param. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpNumberMatch(int16 selected_param, unsigned long match, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpNumberMatch opcode (void pointers are cast to numbers). 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param: index of the input argument. It must be an void* or the 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // evaluation result will generate a EVAL_ERROR. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match: the pointer numeric value to compare against selected_param. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpVoidPtrMatch(int16 selected_param, const void* match, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpUlongMatchRange opcode using the memory passed in the ctor. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param: index of the input argument. It must be a ulong or the 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // evaluation result will generate a EVAL_ERROR. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lower_bound, upper_bound: the range to compare against selected_param. 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpUlongMatchRange(int16 selected_param, 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long lower_bound, 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long upper_bound, 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpWStringMatch opcode using the raw memory passed in the ctor. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param: index of the input argument. It must be a wide string 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pointer or the evaluation result will generate a EVAL_ERROR. 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match_str: string to compare against selected_param. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start_position: when its value is from 0 to < 0x7fff it indicates an 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // offset from the selected_param string where to perform the comparison. If 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the value is SeekForward then a substring search is performed. If the 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value is SeekToEnd the comparison is performed against the last part of 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the selected_param string. 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that the range in the position (0 to 0x7fff) is dictated by the 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // current implementation. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match_opts: Indicates additional matching flags. Currently CaseInsensitive 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is supported. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpWStringMatch(int16 selected_param, 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const wchar_t* match_str, 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_position, 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringMatchOptions match_opts, 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates an OpUlongAndMatch opcode using the raw memory passed in the ctor. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param: index of the input argument. It must be ulong or the 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // evaluation result will generate a EVAL_ERROR. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // match: the value to bitwise AND against selected_param. 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeOpUlongAndMatch(int16 selected_param, 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long match, 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 options); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constructs the common part of every opcode. selected_param is the index 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the input param to use when evaluating the opcode. Pass -1 in 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // selected_param to indicate that no input parameter is required. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PolicyOpcode* MakeBase(OpcodeID opcode_id, uint32 options, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int16 selected_param); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocates (and copies) a string (of size length) inside the buffer and 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // returns the displacement with respect to start. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptrdiff_t AllocRelative(void* start, const wchar_t* str, size_t lenght); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Points to the lowest currently available address of the memory 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used to make the opcodes. This pointer increments as opcodes are made. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* memory_top_; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Points to the highest currently available address of the memory 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used to make the opcodes. This pointer decrements as opcode strings are 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocated. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* memory_bottom_; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(OpcodeFactory); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace sandbox 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_ 381