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__