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 ((size > sizeof(*this)) || 239 (param_info_[index].offset_ > (sizeof(*this) - size))) { 240 // It does not fit, abort copy. 241 return false; 242 } 243 244 char* dest = reinterpret_cast<char*>(this) + param_info_[index].offset_; 245 246 // We might be touching user memory, this has to be done from inside a try 247 // except. 248 __try { 249 memcpy(dest, parameter_address, size); 250 } 251 __except(EXCEPTION_EXECUTE_HANDLER) { 252 return false; 253 } 254 255 // Set the flag to tell the broker to update the buffer once the call is 256 // made. 257 if (is_in_out) 258 SetIsInOut(true); 259 260 param_info_[index + 1].offset_ = Align(param_info_[index].offset_ + 261 size); 262 param_info_[index].size_ = size; 263 param_info_[index].type_ = type; 264 return true; 265 } 266 267 // Returns a pointer to a parameter in the memory section. 268 void* GetParamPtr(size_t index) { 269 return reinterpret_cast<char*>(this) + param_info_[index].offset_; 270 } 271 272 // Returns the total size of the buffer. Only valid once all the paramters 273 // have been copied in with CopyParamIn. 274 uint32 GetSize() const { 275 return param_info_[NUMBER_PARAMS].offset_; 276 } 277 278 protected: 279 ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { } 280 281 private: 282 ParamInfo param_info_[NUMBER_PARAMS + 1]; 283 char parameters_[BLOCK_SIZE - sizeof(CrossCallParams) 284 - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)]; 285 DISALLOW_COPY_AND_ASSIGN(ActualCallParams); 286 }; 287 288 COMPILE_ASSERT(sizeof(ActualCallParams<1, 1024>) == 1024, bad_size_buffer); 289 COMPILE_ASSERT(sizeof(ActualCallParams<2, 1024>) == 1024, bad_size_buffer); 290 COMPILE_ASSERT(sizeof(ActualCallParams<3, 1024>) == 1024, bad_size_buffer); 291 292 } // namespace sandbox 293 294 #endif // SANDBOX_SRC_CROSSCALL_PARAMS_H__ 295