security/sandbox/win/src/crosscall_params.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial