Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2012 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_SRC_CROSSCALL_PARAMS_H__
      6 #define SANDBOX_SRC_CROSSCALL_PARAMS_H__
      7 
      8 #include <windows.h>
      9 #include <lmaccess.h>
     10 
     11 #include <memory>
     12 
     13 #include "base/basictypes.h"
     14 #include "sandbox/win/src/internal_types.h"
     15 #include "sandbox/win/src/sandbox_types.h"
     16 
     17 namespace {
     18 
     19 // Increases |value| until there is no need for padding given an int64
     20 // alignment. Returns the increased value.
     21 uint32 Align(uint32 value) {
     22   uint32 alignment = sizeof(int64);
     23   return ((value + alignment - 1) / alignment) * alignment;
     24 }
     25 
     26 }
     27 // This header is part of CrossCall: the sandbox inter-process communication.
     28 // This header defines the basic types used both in the client IPC and in the
     29 // server IPC code. CrossCallParams and ActualCallParams model the input
     30 // parameters of an IPC call and CrossCallReturn models the output params and
     31 // the return value.
     32 //
     33 // An IPC call is defined by its 'tag' which is a (uint32) unique identifier
     34 // that is used to route the IPC call to the proper server. Every tag implies
     35 // a complete call signature including the order and type of each parameter.
     36 //
     37 // Like most IPC systems. CrossCall is designed to take as inputs 'simple'
     38 // types such as integers and strings. Classes, generic arrays or pointers to
     39 // them are not supported.
     40 //
     41 // Another limitation of CrossCall is that the return value and output
     42 // parameters can only be uint32 integers. Returning complex structures or
     43 // strings is not supported.
     44 
     45 namespace sandbox {
     46 
     47 // max number of extended return parameters. See CrossCallReturn
     48 const size_t kExtendedReturnCount = 8;
     49 
     50 // Union of multiple types to be used as extended results
     51 // in the CrossCallReturn.
     52 union MultiType {
     53   uint32 unsigned_int;
     54   void* pointer;
     55   HANDLE handle;
     56   ULONG_PTR ulong_ptr;
     57 };
     58 
     59 // Maximum number of IPC parameters currently supported.
     60 // To increase this value, we have to:
     61 //  - Add another Callback typedef to Dispatcher.
     62 //  - Add another case to the switch on SharedMemIPCServer::InvokeCallback.
     63 //  - Add another case to the switch in GetActualAndMaxBufferSize
     64 const int kMaxIpcParams = 9;
     65 
     66 // Contains the information about a parameter in the ipc buffer.
     67 struct ParamInfo {
     68   ArgType type_;
     69   uint32 offset_;
     70   uint32 size_;
     71 };
     72 
     73 // Models the return value and the return parameters of an IPC call
     74 // currently limited to one status code and eight generic return values
     75 // which cannot be pointers to other data. For x64 ports this structure
     76 // might have to use other integer types.
     77 struct CrossCallReturn {
     78   // the IPC tag. It should match the original IPC tag.
     79   uint32 tag;
     80   // The result of the IPC operation itself.
     81   ResultCode call_outcome;
     82   // the result of the IPC call as executed in the server. The interpretation
     83   // of this value depends on the specific service.
     84   union {
     85     NTSTATUS nt_status;
     86     DWORD    win32_result;
     87   };
     88   // Number of extended return values.
     89   uint32 extended_count;
     90   // for calls that should return a windows handle. It is found here.
     91   HANDLE handle;
     92   // The array of extended values.
     93   MultiType extended[kExtendedReturnCount];
     94 };
     95 
     96 // CrossCallParams base class that models the input params all packed in a
     97 // single compact memory blob. The representation can vary but in general a
     98 // given child of this class is meant to represent all input parameters
     99 // necessary to make a IPC call.
    100 //
    101 // This class cannot have virtual members because its assumed the IPC
    102 // parameters start from the 'this' pointer to the end, which is defined by
    103 // one of the subclasses
    104 //
    105 // Objects of this class cannot be constructed directly. Only derived
    106 // classes have the proper knowledge to construct it.
    107 class CrossCallParams {
    108  public:
    109   // Returns the tag (ipc unique id) associated with this IPC.
    110   uint32 GetTag() const {
    111     return tag_;
    112   }
    113 
    114   // Returns the beggining of the buffer where the IPC params can be stored.
    115   // prior to an IPC call
    116   const void* GetBuffer() const {
    117     return this;
    118   }
    119 
    120   // Returns how many parameter this IPC call should have.
    121   const uint32 GetParamsCount() const {
    122     return params_count_;
    123   }
    124 
    125   // Returns a pointer to the CrossCallReturn structure.
    126   CrossCallReturn* GetCallReturn() {
    127     return &call_return;
    128   }
    129 
    130   // Returns TRUE if this call contains InOut parameters.
    131   const bool IsInOut() const {
    132     return (1 == is_in_out_);
    133   }
    134 
    135   // Tells the CrossCall object if it contains InOut parameters.
    136   void SetIsInOut(bool value) {
    137     if (value)
    138       is_in_out_ = 1;
    139     else
    140       is_in_out_ = 0;
    141   }
    142 
    143  protected:
    144   // constructs the IPC call params. Called only from the derived classes
    145   CrossCallParams(uint32 tag, uint32 params_count)
    146       : tag_(tag),
    147         params_count_(params_count),
    148         is_in_out_(0) {
    149   }
    150 
    151  private:
    152   uint32 tag_;
    153   uint32 is_in_out_;
    154   CrossCallReturn call_return;
    155   const uint32 params_count_;
    156   DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
    157 };
    158 
    159 // ActualCallParams models an specific IPC call parameters with respect to the
    160 // storage allocation that the packed parameters should need.
    161 // NUMBER_PARAMS: the number of parameters, valid from 1 to N
    162 // BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take,
    163 // typically the block size is defined by the channel size of the underlying
    164 // ipc mechanism.
    165 // In practice this class is used to levergage C++ capacity to properly
    166 // calculate sizes and displacements given the possibility of the packed params
    167 // blob to be complex.
    168 //
    169 // As is, this class assumes that the layout of the blob is as follows. Assume
    170 // that NUMBER_PARAMS = 2 and a 32-bit build:
    171 //
    172 // [ tag                4 bytes]
    173 // [ IsOnOut            4 bytes]
    174 // [ call return       52 bytes]
    175 // [ params count       4 bytes]
    176 // [ parameter 0 type   4 bytes]
    177 // [ parameter 0 offset 4 bytes] ---delta to ---\
    178 // [ parameter 0 size   4 bytes]                |
    179 // [ parameter 1 type   4 bytes]                |
    180 // [ parameter 1 offset 4 bytes] ---------------|--\
    181 // [ parameter 1 size   4 bytes]                |  |
    182 // [ parameter 2 type   4 bytes]                |  |
    183 // [ parameter 2 offset 4 bytes] ----------------------\
    184 // [ parameter 2 size   4 bytes]                |  |   |
    185 // |---------------------------|                |  |   |
    186 // | value 0     (x bytes)     | <--------------/  |   |
    187 // | value 1     (y bytes)     | <-----------------/   |
    188 // |                           |                       |
    189 // | end of buffer             | <---------------------/
    190 // |---------------------------|
    191 //
    192 // Note that the actual number of params is NUMBER_PARAMS + 1
    193 // so that the size of each actual param can be computed from the difference
    194 // between one parameter and the next down. The offset of the last param
    195 // points to the end of the buffer and the type and size are undefined.
    196 //
    197 template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
    198 class ActualCallParams : public CrossCallParams {
    199  public:
    200   // constructor. Pass the ipc unique tag as input
    201   explicit ActualCallParams(uint32 tag)
    202       : CrossCallParams(tag, NUMBER_PARAMS) {
    203     param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this);
    204   }
    205 
    206   // Testing-only constructor. Allows setting the |number_params| to a
    207   // wrong value.
    208   ActualCallParams(uint32 tag, uint32 number_params)
    209       : CrossCallParams(tag, number_params) {
    210     param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this);
    211   }
    212 
    213   // Testing-only method. Allows setting the apparent size to a wrong value.
    214   // returns the previous size.
    215   uint32 OverrideSize(uint32 new_size) {
    216     uint32 previous_size = param_info_[NUMBER_PARAMS].offset_;
    217     param_info_[NUMBER_PARAMS].offset_ = new_size;
    218     return previous_size;
    219   }
    220 
    221   // Copies each paramter into the internal buffer. For each you must supply:
    222   // index: 0 for the first param, 1 for the next an so on
    223   bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size,
    224                    bool is_in_out, ArgType type) {
    225     if (index >= NUMBER_PARAMS) {
    226       return false;
    227     }
    228 
    229     if (kuint32max == size) {
    230       // Memory error while getting the size.
    231       return false;
    232     }
    233 
    234     if (size && !parameter_address) {
    235       return false;
    236     }
    237 
    238     if (param_info_[index].offset_ > sizeof(*this)) {
    239       // It does not fit, abort copy.
    240       return false;
    241     }
    242 
    243     char* dest = reinterpret_cast<char*>(this) +  param_info_[index].offset_;
    244 
    245     // We might be touching user memory, this has to be done from inside a try
    246     // except.
    247     __try {
    248       memcpy(dest, parameter_address, size);
    249     }
    250     __except(EXCEPTION_EXECUTE_HANDLER) {
    251       return false;
    252     }
    253 
    254     // Set the flag to tell the broker to update the buffer once the call is
    255     // made.
    256     if (is_in_out)
    257       SetIsInOut(true);
    258 
    259     param_info_[index + 1].offset_ = Align(param_info_[index].offset_ +
    260                                                 size);
    261     param_info_[index].size_ = size;
    262     param_info_[index].type_ = type;
    263     return true;
    264   }
    265 
    266   // Returns a pointer to a parameter in the memory section.
    267   void* GetParamPtr(size_t index) {
    268     return reinterpret_cast<char*>(this) + param_info_[index].offset_;
    269   }
    270 
    271   // Returns the total size of the buffer. Only valid once all the paramters
    272   // have been copied in with CopyParamIn.
    273   uint32 GetSize() const {
    274     return param_info_[NUMBER_PARAMS].offset_;
    275   }
    276 
    277  protected:
    278   ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
    279 
    280  private:
    281   ParamInfo param_info_[NUMBER_PARAMS + 1];
    282   char parameters_[BLOCK_SIZE - sizeof(CrossCallParams)
    283                    - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
    284   DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
    285 };
    286 
    287 COMPILE_ASSERT(sizeof(ActualCallParams<1, 1024>) == 1024, bad_size_buffer);
    288 COMPILE_ASSERT(sizeof(ActualCallParams<2, 1024>) == 1024, bad_size_buffer);
    289 COMPILE_ASSERT(sizeof(ActualCallParams<3, 1024>) == 1024, bad_size_buffer);
    290 
    291 }  // namespace sandbox
    292 
    293 #endif  // SANDBOX_SRC_CROSSCALL_PARAMS_H__
    294