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