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