security/sandbox/win/src/crosscall_params.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/sandbox/win/src/crosscall_params.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,293 @@
     1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#ifndef SANDBOX_SRC_CROSSCALL_PARAMS_H__
     1.9 +#define SANDBOX_SRC_CROSSCALL_PARAMS_H__
    1.10 +
    1.11 +#include <windows.h>
    1.12 +#include <lmaccess.h>
    1.13 +
    1.14 +#include <memory>
    1.15 +
    1.16 +#include "base/basictypes.h"
    1.17 +#include "sandbox/win/src/internal_types.h"
    1.18 +#include "sandbox/win/src/sandbox_types.h"
    1.19 +
    1.20 +namespace {
    1.21 +
    1.22 +// Increases |value| until there is no need for padding given an int64
    1.23 +// alignment. Returns the increased value.
    1.24 +uint32 Align(uint32 value) {
    1.25 +  uint32 alignment = sizeof(int64);
    1.26 +  return ((value + alignment - 1) / alignment) * alignment;
    1.27 +}
    1.28 +
    1.29 +}
    1.30 +// This header is part of CrossCall: the sandbox inter-process communication.
    1.31 +// This header defines the basic types used both in the client IPC and in the
    1.32 +// server IPC code. CrossCallParams and ActualCallParams model the input
    1.33 +// parameters of an IPC call and CrossCallReturn models the output params and
    1.34 +// the return value.
    1.35 +//
    1.36 +// An IPC call is defined by its 'tag' which is a (uint32) unique identifier
    1.37 +// that is used to route the IPC call to the proper server. Every tag implies
    1.38 +// a complete call signature including the order and type of each parameter.
    1.39 +//
    1.40 +// Like most IPC systems. CrossCall is designed to take as inputs 'simple'
    1.41 +// types such as integers and strings. Classes, generic arrays or pointers to
    1.42 +// them are not supported.
    1.43 +//
    1.44 +// Another limitation of CrossCall is that the return value and output
    1.45 +// parameters can only be uint32 integers. Returning complex structures or
    1.46 +// strings is not supported.
    1.47 +
    1.48 +namespace sandbox {
    1.49 +
    1.50 +// max number of extended return parameters. See CrossCallReturn
    1.51 +const size_t kExtendedReturnCount = 8;
    1.52 +
    1.53 +// Union of multiple types to be used as extended results
    1.54 +// in the CrossCallReturn.
    1.55 +union MultiType {
    1.56 +  uint32 unsigned_int;
    1.57 +  void* pointer;
    1.58 +  HANDLE handle;
    1.59 +  ULONG_PTR ulong_ptr;
    1.60 +};
    1.61 +
    1.62 +// Maximum number of IPC parameters currently supported.
    1.63 +// To increase this value, we have to:
    1.64 +//  - Add another Callback typedef to Dispatcher.
    1.65 +//  - Add another case to the switch on SharedMemIPCServer::InvokeCallback.
    1.66 +//  - Add another case to the switch in GetActualAndMaxBufferSize
    1.67 +const int kMaxIpcParams = 9;
    1.68 +
    1.69 +// Contains the information about a parameter in the ipc buffer.
    1.70 +struct ParamInfo {
    1.71 +  ArgType type_;
    1.72 +  uint32 offset_;
    1.73 +  uint32 size_;
    1.74 +};
    1.75 +
    1.76 +// Models the return value and the return parameters of an IPC call
    1.77 +// currently limited to one status code and eight generic return values
    1.78 +// which cannot be pointers to other data. For x64 ports this structure
    1.79 +// might have to use other integer types.
    1.80 +struct CrossCallReturn {
    1.81 +  // the IPC tag. It should match the original IPC tag.
    1.82 +  uint32 tag;
    1.83 +  // The result of the IPC operation itself.
    1.84 +  ResultCode call_outcome;
    1.85 +  // the result of the IPC call as executed in the server. The interpretation
    1.86 +  // of this value depends on the specific service.
    1.87 +  union {
    1.88 +    NTSTATUS nt_status;
    1.89 +    DWORD    win32_result;
    1.90 +  };
    1.91 +  // Number of extended return values.
    1.92 +  uint32 extended_count;
    1.93 +  // for calls that should return a windows handle. It is found here.
    1.94 +  HANDLE handle;
    1.95 +  // The array of extended values.
    1.96 +  MultiType extended[kExtendedReturnCount];
    1.97 +};
    1.98 +
    1.99 +// CrossCallParams base class that models the input params all packed in a
   1.100 +// single compact memory blob. The representation can vary but in general a
   1.101 +// given child of this class is meant to represent all input parameters
   1.102 +// necessary to make a IPC call.
   1.103 +//
   1.104 +// This class cannot have virtual members because its assumed the IPC
   1.105 +// parameters start from the 'this' pointer to the end, which is defined by
   1.106 +// one of the subclasses
   1.107 +//
   1.108 +// Objects of this class cannot be constructed directly. Only derived
   1.109 +// classes have the proper knowledge to construct it.
   1.110 +class CrossCallParams {
   1.111 + public:
   1.112 +  // Returns the tag (ipc unique id) associated with this IPC.
   1.113 +  uint32 GetTag() const {
   1.114 +    return tag_;
   1.115 +  }
   1.116 +
   1.117 +  // Returns the beggining of the buffer where the IPC params can be stored.
   1.118 +  // prior to an IPC call
   1.119 +  const void* GetBuffer() const {
   1.120 +    return this;
   1.121 +  }
   1.122 +
   1.123 +  // Returns how many parameter this IPC call should have.
   1.124 +  const uint32 GetParamsCount() const {
   1.125 +    return params_count_;
   1.126 +  }
   1.127 +
   1.128 +  // Returns a pointer to the CrossCallReturn structure.
   1.129 +  CrossCallReturn* GetCallReturn() {
   1.130 +    return &call_return;
   1.131 +  }
   1.132 +
   1.133 +  // Returns TRUE if this call contains InOut parameters.
   1.134 +  const bool IsInOut() const {
   1.135 +    return (1 == is_in_out_);
   1.136 +  }
   1.137 +
   1.138 +  // Tells the CrossCall object if it contains InOut parameters.
   1.139 +  void SetIsInOut(bool value) {
   1.140 +    if (value)
   1.141 +      is_in_out_ = 1;
   1.142 +    else
   1.143 +      is_in_out_ = 0;
   1.144 +  }
   1.145 +
   1.146 + protected:
   1.147 +  // constructs the IPC call params. Called only from the derived classes
   1.148 +  CrossCallParams(uint32 tag, uint32 params_count)
   1.149 +      : tag_(tag),
   1.150 +        params_count_(params_count),
   1.151 +        is_in_out_(0) {
   1.152 +  }
   1.153 +
   1.154 + private:
   1.155 +  uint32 tag_;
   1.156 +  uint32 is_in_out_;
   1.157 +  CrossCallReturn call_return;
   1.158 +  const uint32 params_count_;
   1.159 +  DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
   1.160 +};
   1.161 +
   1.162 +// ActualCallParams models an specific IPC call parameters with respect to the
   1.163 +// storage allocation that the packed parameters should need.
   1.164 +// NUMBER_PARAMS: the number of parameters, valid from 1 to N
   1.165 +// BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take,
   1.166 +// typically the block size is defined by the channel size of the underlying
   1.167 +// ipc mechanism.
   1.168 +// In practice this class is used to levergage C++ capacity to properly
   1.169 +// calculate sizes and displacements given the possibility of the packed params
   1.170 +// blob to be complex.
   1.171 +//
   1.172 +// As is, this class assumes that the layout of the blob is as follows. Assume
   1.173 +// that NUMBER_PARAMS = 2 and a 32-bit build:
   1.174 +//
   1.175 +// [ tag                4 bytes]
   1.176 +// [ IsOnOut            4 bytes]
   1.177 +// [ call return       52 bytes]
   1.178 +// [ params count       4 bytes]
   1.179 +// [ parameter 0 type   4 bytes]
   1.180 +// [ parameter 0 offset 4 bytes] ---delta to ---\
   1.181 +// [ parameter 0 size   4 bytes]                |
   1.182 +// [ parameter 1 type   4 bytes]                |
   1.183 +// [ parameter 1 offset 4 bytes] ---------------|--\
   1.184 +// [ parameter 1 size   4 bytes]                |  |
   1.185 +// [ parameter 2 type   4 bytes]                |  |
   1.186 +// [ parameter 2 offset 4 bytes] ----------------------\
   1.187 +// [ parameter 2 size   4 bytes]                |  |   |
   1.188 +// |---------------------------|                |  |   |
   1.189 +// | value 0     (x bytes)     | <--------------/  |   |
   1.190 +// | value 1     (y bytes)     | <-----------------/   |
   1.191 +// |                           |                       |
   1.192 +// | end of buffer             | <---------------------/
   1.193 +// |---------------------------|
   1.194 +//
   1.195 +// Note that the actual number of params is NUMBER_PARAMS + 1
   1.196 +// so that the size of each actual param can be computed from the difference
   1.197 +// between one parameter and the next down. The offset of the last param
   1.198 +// points to the end of the buffer and the type and size are undefined.
   1.199 +//
   1.200 +template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
   1.201 +class ActualCallParams : public CrossCallParams {
   1.202 + public:
   1.203 +  // constructor. Pass the ipc unique tag as input
   1.204 +  explicit ActualCallParams(uint32 tag)
   1.205 +      : CrossCallParams(tag, NUMBER_PARAMS) {
   1.206 +    param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this);
   1.207 +  }
   1.208 +
   1.209 +  // Testing-only constructor. Allows setting the |number_params| to a
   1.210 +  // wrong value.
   1.211 +  ActualCallParams(uint32 tag, uint32 number_params)
   1.212 +      : CrossCallParams(tag, number_params) {
   1.213 +    param_info_[0].offset_ = parameters_ - reinterpret_cast<char*>(this);
   1.214 +  }
   1.215 +
   1.216 +  // Testing-only method. Allows setting the apparent size to a wrong value.
   1.217 +  // returns the previous size.
   1.218 +  uint32 OverrideSize(uint32 new_size) {
   1.219 +    uint32 previous_size = param_info_[NUMBER_PARAMS].offset_;
   1.220 +    param_info_[NUMBER_PARAMS].offset_ = new_size;
   1.221 +    return previous_size;
   1.222 +  }
   1.223 +
   1.224 +  // Copies each paramter into the internal buffer. For each you must supply:
   1.225 +  // index: 0 for the first param, 1 for the next an so on
   1.226 +  bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size,
   1.227 +                   bool is_in_out, ArgType type) {
   1.228 +    if (index >= NUMBER_PARAMS) {
   1.229 +      return false;
   1.230 +    }
   1.231 +
   1.232 +    if (kuint32max == size) {
   1.233 +      // Memory error while getting the size.
   1.234 +      return false;
   1.235 +    }
   1.236 +
   1.237 +    if (size && !parameter_address) {
   1.238 +      return false;
   1.239 +    }
   1.240 +
   1.241 +    if (param_info_[index].offset_ > sizeof(*this)) {
   1.242 +      // It does not fit, abort copy.
   1.243 +      return false;
   1.244 +    }
   1.245 +
   1.246 +    char* dest = reinterpret_cast<char*>(this) +  param_info_[index].offset_;
   1.247 +
   1.248 +    // We might be touching user memory, this has to be done from inside a try
   1.249 +    // except.
   1.250 +    __try {
   1.251 +      memcpy(dest, parameter_address, size);
   1.252 +    }
   1.253 +    __except(EXCEPTION_EXECUTE_HANDLER) {
   1.254 +      return false;
   1.255 +    }
   1.256 +
   1.257 +    // Set the flag to tell the broker to update the buffer once the call is
   1.258 +    // made.
   1.259 +    if (is_in_out)
   1.260 +      SetIsInOut(true);
   1.261 +
   1.262 +    param_info_[index + 1].offset_ = Align(param_info_[index].offset_ +
   1.263 +                                                size);
   1.264 +    param_info_[index].size_ = size;
   1.265 +    param_info_[index].type_ = type;
   1.266 +    return true;
   1.267 +  }
   1.268 +
   1.269 +  // Returns a pointer to a parameter in the memory section.
   1.270 +  void* GetParamPtr(size_t index) {
   1.271 +    return reinterpret_cast<char*>(this) + param_info_[index].offset_;
   1.272 +  }
   1.273 +
   1.274 +  // Returns the total size of the buffer. Only valid once all the paramters
   1.275 +  // have been copied in with CopyParamIn.
   1.276 +  uint32 GetSize() const {
   1.277 +    return param_info_[NUMBER_PARAMS].offset_;
   1.278 +  }
   1.279 +
   1.280 + protected:
   1.281 +  ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
   1.282 +
   1.283 + private:
   1.284 +  ParamInfo param_info_[NUMBER_PARAMS + 1];
   1.285 +  char parameters_[BLOCK_SIZE - sizeof(CrossCallParams)
   1.286 +                   - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
   1.287 +  DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
   1.288 +};
   1.289 +
   1.290 +COMPILE_ASSERT(sizeof(ActualCallParams<1, 1024>) == 1024, bad_size_buffer);
   1.291 +COMPILE_ASSERT(sizeof(ActualCallParams<2, 1024>) == 1024, bad_size_buffer);
   1.292 +COMPILE_ASSERT(sizeof(ActualCallParams<3, 1024>) == 1024, bad_size_buffer);
   1.293 +
   1.294 +}  // namespace sandbox
   1.295 +
   1.296 +#endif  // SANDBOX_SRC_CROSSCALL_PARAMS_H__

mercurial