1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/crosscall_client.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,483 @@ 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_CLIENT_H_ 1.9 +#define SANDBOX_SRC_CROSSCALL_CLIENT_H_ 1.10 + 1.11 +#include "sandbox/win/src/crosscall_params.h" 1.12 +#include "sandbox/win/src/sandbox.h" 1.13 + 1.14 +// This header defines the CrossCall(..) family of templated functions 1.15 +// Their purpose is to simulate the syntax of regular call but to generate 1.16 +// and IPC from the client-side. 1.17 +// 1.18 +// The basic pattern is to 1.19 +// 1) use template argument deduction to compute the size of each 1.20 +// parameter and the appropriate copy method 1.21 +// 2) pack the parameters in the appropriate ActualCallParams< > object 1.22 +// 3) call the IPC interface IPCProvider::DoCall( ) 1.23 +// 1.24 +// The general interface of CrossCall is: 1.25 +// ResultCode CrossCall(IPCProvider& ipc_provider, 1.26 +// uint32 tag, 1.27 +// const Par1& p1, const Par2& p2,...pn 1.28 +// CrossCallReturn* answer) 1.29 +// 1.30 +// where: 1.31 +// ipc_provider: is a specific implementation of the ipc transport see 1.32 +// sharedmem_ipc_server.h for an example. 1.33 +// tag : is the unique id for this IPC call. Is used to route the call to 1.34 +// the appropriate service. 1.35 +// p1, p2,.. pn : The input parameters of the IPC. Use only simple types 1.36 +// and wide strings (can add support for others). 1.37 +// answer : If the IPC was successful. The server-side answer is here. The 1.38 +// interpretation of the answer is private to client and server. 1.39 +// 1.40 +// The return value is ALL_OK if the IPC was delivered to the server, other 1.41 +// return codes indicate that the IPC transport failed to deliver it. 1.42 +namespace sandbox { 1.43 + 1.44 +// this is the assumed channel size. This can be overridden in a given 1.45 +// IPC implementation. 1.46 +const uint32 kIPCChannelSize = 1024; 1.47 + 1.48 +// The copy helper uses templates to deduce the appropriate copy function to 1.49 +// copy the input parameters in the buffer that is going to be send across the 1.50 +// IPC. These template facility can be made more sophisticated as need arises. 1.51 + 1.52 +// The default copy helper. It catches the general case where no other 1.53 +// specialized template matches better. We set the type to ULONG_TYPE, so this 1.54 +// only works with objects whose size is 32 bits. 1.55 +template<typename T> 1.56 +class CopyHelper { 1.57 + public: 1.58 + CopyHelper(const T& t) : t_(t) {} 1.59 + 1.60 + // Returns the pointer to the start of the input. 1.61 + const void* GetStart() const { 1.62 + return &t_; 1.63 + } 1.64 + 1.65 + // Update the stored value with the value in the buffer. This is not 1.66 + // supported for this type. 1.67 + bool Update(void* buffer) { 1.68 + // Not supported; 1.69 + return true; 1.70 + } 1.71 + 1.72 + // Returns the size of the input in bytes. 1.73 + uint32 GetSize() const { 1.74 + return sizeof(T); 1.75 + } 1.76 + 1.77 + // Returns true if the current type is used as an In or InOut parameter. 1.78 + bool IsInOut() { 1.79 + return false; 1.80 + } 1.81 + 1.82 + // Returns this object's type. 1.83 + ArgType GetType() { 1.84 + COMPILE_ASSERT(sizeof(T) == sizeof(uint32), need_specialization); 1.85 + return ULONG_TYPE; 1.86 + } 1.87 + 1.88 + private: 1.89 + const T& t_; 1.90 +}; 1.91 + 1.92 +// This copy helper template specialization if for the void pointer 1.93 +// case both 32 and 64 bit. 1.94 +template<> 1.95 +class CopyHelper<void*> { 1.96 + public: 1.97 + CopyHelper(void* t) : t_(t) {} 1.98 + 1.99 + // Returns the pointer to the start of the input. 1.100 + const void* GetStart() const { 1.101 + return &t_; 1.102 + } 1.103 + 1.104 + // Update the stored value with the value in the buffer. This is not 1.105 + // supported for this type. 1.106 + bool Update(void* buffer) { 1.107 + // Not supported; 1.108 + return true; 1.109 + } 1.110 + 1.111 + // Returns the size of the input in bytes. 1.112 + uint32 GetSize() const { 1.113 + return sizeof(t_); 1.114 + } 1.115 + 1.116 + // Returns true if the current type is used as an In or InOut parameter. 1.117 + bool IsInOut() { 1.118 + return false; 1.119 + } 1.120 + 1.121 + // Returns this object's type. 1.122 + ArgType GetType() { 1.123 + return VOIDPTR_TYPE; 1.124 + } 1.125 + 1.126 + private: 1.127 + const void* t_; 1.128 +}; 1.129 + 1.130 +// This copy helper template specialization catches the cases where the 1.131 +// parameter is a pointer to a string. 1.132 +template<> 1.133 +class CopyHelper<const wchar_t*> { 1.134 + public: 1.135 + CopyHelper(const wchar_t* t) 1.136 + : t_(t) { 1.137 + } 1.138 + 1.139 + // Returns the pointer to the start of the string. 1.140 + const void* GetStart() const { 1.141 + return t_; 1.142 + } 1.143 + 1.144 + // Update the stored value with the value in the buffer. This is not 1.145 + // supported for this type. 1.146 + bool Update(void* buffer) { 1.147 + // Not supported; 1.148 + return true; 1.149 + } 1.150 + 1.151 + // Returns the size of the string in bytes. We define a NULL string to 1.152 + // be of zero length. 1.153 + uint32 GetSize() const { 1.154 + __try { 1.155 + return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0])); 1.156 + } 1.157 + __except(EXCEPTION_EXECUTE_HANDLER) { 1.158 + return kuint32max; 1.159 + } 1.160 + } 1.161 + 1.162 + // Returns true if the current type is used as an In or InOut parameter. 1.163 + bool IsInOut() { 1.164 + return false; 1.165 + } 1.166 + 1.167 + ArgType GetType() { 1.168 + return WCHAR_TYPE; 1.169 + } 1.170 + 1.171 + private: 1.172 + // We provide our not very optimized version of wcslen(), since we don't 1.173 + // want to risk having the linker use the version in the CRT since the CRT 1.174 + // might not be present when we do an early IPC call. 1.175 + static size_t __cdecl StringLength(const wchar_t* wcs) { 1.176 + const wchar_t *eos = wcs; 1.177 + while (*eos++); 1.178 + return static_cast<size_t>(eos - wcs - 1); 1.179 + } 1.180 + 1.181 + const wchar_t* t_; 1.182 +}; 1.183 + 1.184 +// Specialization for non-const strings. We just reuse the implementation of the 1.185 +// const string specialization. 1.186 +template<> 1.187 +class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> { 1.188 + public: 1.189 + typedef CopyHelper<const wchar_t*> Base; 1.190 + CopyHelper(wchar_t* t) : Base(t) {} 1.191 + 1.192 + const void* GetStart() const { 1.193 + return Base::GetStart(); 1.194 + } 1.195 + 1.196 + bool Update(void* buffer) { 1.197 + return Base::Update(buffer); 1.198 + } 1.199 + 1.200 + uint32 GetSize() const { 1.201 + return Base::GetSize(); 1.202 + } 1.203 + 1.204 + bool IsInOut() { 1.205 + return Base::IsInOut(); 1.206 + } 1.207 + 1.208 + ArgType GetType() { 1.209 + return Base::GetType(); 1.210 + } 1.211 +}; 1.212 + 1.213 +// Specialization for wchar_t arrays strings. We just reuse the implementation 1.214 +// of the const string specialization. 1.215 +template<size_t n> 1.216 +class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> { 1.217 + public: 1.218 + typedef const wchar_t array[n]; 1.219 + typedef CopyHelper<const wchar_t*> Base; 1.220 + CopyHelper(array t) : Base(t) {} 1.221 + 1.222 + const void* GetStart() const { 1.223 + return Base::GetStart(); 1.224 + } 1.225 + 1.226 + bool Update(void* buffer) { 1.227 + return Base::Update(buffer); 1.228 + } 1.229 + 1.230 + uint32 GetSize() const { 1.231 + return Base::GetSize(); 1.232 + } 1.233 + 1.234 + bool IsInOut() { 1.235 + return Base::IsInOut(); 1.236 + } 1.237 + 1.238 + ArgType GetType() { 1.239 + return Base::GetType(); 1.240 + } 1.241 +}; 1.242 + 1.243 +// Generic encapsulation class containing a pointer to a buffer and the 1.244 +// size of the buffer. It is used by the IPC to be able to pass in/out 1.245 +// parameters. 1.246 +class InOutCountedBuffer : public CountedBuffer { 1.247 + public: 1.248 + InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {} 1.249 +}; 1.250 + 1.251 +// This copy helper template specialization catches the cases where the 1.252 +// parameter is a an input/output buffer. 1.253 +template<> 1.254 +class CopyHelper<InOutCountedBuffer> { 1.255 + public: 1.256 + CopyHelper(const InOutCountedBuffer t) : t_(t) {} 1.257 + 1.258 + // Returns the pointer to the start of the string. 1.259 + const void* GetStart() const { 1.260 + return t_.Buffer(); 1.261 + } 1.262 + 1.263 + // Updates the buffer with the value from the new buffer in parameter. 1.264 + bool Update(void* buffer) { 1.265 + // We are touching user memory, this has to be done from inside a try 1.266 + // except. 1.267 + __try { 1.268 + memcpy(t_.Buffer(), buffer, t_.Size()); 1.269 + } 1.270 + __except(EXCEPTION_EXECUTE_HANDLER) { 1.271 + return false; 1.272 + } 1.273 + return true; 1.274 + } 1.275 + 1.276 + // Returns the size of the string in bytes. We define a NULL string to 1.277 + // be of zero length. 1.278 + uint32 GetSize() const { 1.279 + return t_.Size(); 1.280 + } 1.281 + 1.282 + // Returns true if the current type is used as an In or InOut parameter. 1.283 + bool IsInOut() { 1.284 + return true; 1.285 + } 1.286 + 1.287 + ArgType GetType() { 1.288 + return INOUTPTR_TYPE; 1.289 + } 1.290 + 1.291 + private: 1.292 + const InOutCountedBuffer t_; 1.293 +}; 1.294 + 1.295 +// The following two macros make it less error prone the generation 1.296 +// of CrossCall functions with ever more input parameters. 1.297 + 1.298 +#define XCALL_GEN_PARAMS_OBJ(num, params) \ 1.299 + typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \ 1.300 + void* raw_mem = ipc_provider.GetBuffer(); \ 1.301 + if (NULL == raw_mem) \ 1.302 + return SBOX_ERROR_NO_SPACE; \ 1.303 + ActualParams* params = new(raw_mem) ActualParams(tag); 1.304 + 1.305 +#define XCALL_GEN_COPY_PARAM(num, params) \ 1.306 + COMPILE_ASSERT(kMaxIpcParams >= num, too_many_parameters); \ 1.307 + CopyHelper<Par##num> ch##num(p##num); \ 1.308 + if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \ 1.309 + ch##num.IsInOut(), ch##num.GetType())) \ 1.310 + return SBOX_ERROR_NO_SPACE; 1.311 + 1.312 +#define XCALL_GEN_UPDATE_PARAM(num, params) \ 1.313 + if (!ch##num.Update(params->GetParamPtr(num-1))) {\ 1.314 + ipc_provider.FreeBuffer(raw_mem); \ 1.315 + return SBOX_ERROR_BAD_PARAMS; \ 1.316 + } 1.317 + 1.318 +#define XCALL_GEN_FREE_CHANNEL() \ 1.319 + ipc_provider.FreeBuffer(raw_mem); 1.320 + 1.321 +// CrossCall template with one input parameter 1.322 +template <typename IPCProvider, typename Par1> 1.323 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.324 + CrossCallReturn* answer) { 1.325 + XCALL_GEN_PARAMS_OBJ(1, call_params); 1.326 + XCALL_GEN_COPY_PARAM(1, call_params); 1.327 + 1.328 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.329 + 1.330 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.331 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.332 + XCALL_GEN_FREE_CHANNEL(); 1.333 + } 1.334 + 1.335 + return result; 1.336 +} 1.337 + 1.338 +// CrossCall template with two input parameters. 1.339 +template <typename IPCProvider, typename Par1, typename Par2> 1.340 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.341 + const Par2& p2, CrossCallReturn* answer) { 1.342 + XCALL_GEN_PARAMS_OBJ(2, call_params); 1.343 + XCALL_GEN_COPY_PARAM(1, call_params); 1.344 + XCALL_GEN_COPY_PARAM(2, call_params); 1.345 + 1.346 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.347 + 1.348 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.349 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.350 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.351 + XCALL_GEN_FREE_CHANNEL(); 1.352 + } 1.353 + return result; 1.354 +} 1.355 + 1.356 +// CrossCall template with three input parameters. 1.357 +template <typename IPCProvider, typename Par1, typename Par2, typename Par3> 1.358 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.359 + const Par2& p2, const Par3& p3, CrossCallReturn* answer) { 1.360 + XCALL_GEN_PARAMS_OBJ(3, call_params); 1.361 + XCALL_GEN_COPY_PARAM(1, call_params); 1.362 + XCALL_GEN_COPY_PARAM(2, call_params); 1.363 + XCALL_GEN_COPY_PARAM(3, call_params); 1.364 + 1.365 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.366 + 1.367 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.368 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.369 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.370 + XCALL_GEN_UPDATE_PARAM(3, call_params); 1.371 + XCALL_GEN_FREE_CHANNEL(); 1.372 + } 1.373 + return result; 1.374 +} 1.375 + 1.376 +// CrossCall template with four input parameters. 1.377 +template <typename IPCProvider, typename Par1, typename Par2, typename Par3, 1.378 + typename Par4> 1.379 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.380 + const Par2& p2, const Par3& p3, const Par4& p4, 1.381 + CrossCallReturn* answer) { 1.382 + XCALL_GEN_PARAMS_OBJ(4, call_params); 1.383 + XCALL_GEN_COPY_PARAM(1, call_params); 1.384 + XCALL_GEN_COPY_PARAM(2, call_params); 1.385 + XCALL_GEN_COPY_PARAM(3, call_params); 1.386 + XCALL_GEN_COPY_PARAM(4, call_params); 1.387 + 1.388 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.389 + 1.390 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.391 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.392 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.393 + XCALL_GEN_UPDATE_PARAM(3, call_params); 1.394 + XCALL_GEN_UPDATE_PARAM(4, call_params); 1.395 + XCALL_GEN_FREE_CHANNEL(); 1.396 + } 1.397 + return result; 1.398 +} 1.399 + 1.400 +// CrossCall template with five input parameters. 1.401 +template <typename IPCProvider, typename Par1, typename Par2, typename Par3, 1.402 + typename Par4, typename Par5> 1.403 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.404 + const Par2& p2, const Par3& p3, const Par4& p4, 1.405 + const Par5& p5, CrossCallReturn* answer) { 1.406 + XCALL_GEN_PARAMS_OBJ(5, call_params); 1.407 + XCALL_GEN_COPY_PARAM(1, call_params); 1.408 + XCALL_GEN_COPY_PARAM(2, call_params); 1.409 + XCALL_GEN_COPY_PARAM(3, call_params); 1.410 + XCALL_GEN_COPY_PARAM(4, call_params); 1.411 + XCALL_GEN_COPY_PARAM(5, call_params); 1.412 + 1.413 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.414 + 1.415 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.416 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.417 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.418 + XCALL_GEN_UPDATE_PARAM(3, call_params); 1.419 + XCALL_GEN_UPDATE_PARAM(4, call_params); 1.420 + XCALL_GEN_UPDATE_PARAM(5, call_params); 1.421 + XCALL_GEN_FREE_CHANNEL(); 1.422 + } 1.423 + return result; 1.424 +} 1.425 + 1.426 +// CrossCall template with six input parameters. 1.427 +template <typename IPCProvider, typename Par1, typename Par2, typename Par3, 1.428 + typename Par4, typename Par5, typename Par6> 1.429 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.430 + const Par2& p2, const Par3& p3, const Par4& p4, 1.431 + const Par5& p5, const Par6& p6, CrossCallReturn* answer) { 1.432 + XCALL_GEN_PARAMS_OBJ(6, call_params); 1.433 + XCALL_GEN_COPY_PARAM(1, call_params); 1.434 + XCALL_GEN_COPY_PARAM(2, call_params); 1.435 + XCALL_GEN_COPY_PARAM(3, call_params); 1.436 + XCALL_GEN_COPY_PARAM(4, call_params); 1.437 + XCALL_GEN_COPY_PARAM(5, call_params); 1.438 + XCALL_GEN_COPY_PARAM(6, call_params); 1.439 + 1.440 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.441 + 1.442 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.443 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.444 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.445 + XCALL_GEN_UPDATE_PARAM(3, call_params); 1.446 + XCALL_GEN_UPDATE_PARAM(4, call_params); 1.447 + XCALL_GEN_UPDATE_PARAM(5, call_params); 1.448 + XCALL_GEN_UPDATE_PARAM(6, call_params); 1.449 + XCALL_GEN_FREE_CHANNEL(); 1.450 + } 1.451 + return result; 1.452 +} 1.453 + 1.454 +// CrossCall template with seven input parameters. 1.455 +template <typename IPCProvider, typename Par1, typename Par2, typename Par3, 1.456 + typename Par4, typename Par5, typename Par6, typename Par7> 1.457 +ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1, 1.458 + const Par2& p2, const Par3& p3, const Par4& p4, 1.459 + const Par5& p5, const Par6& p6, const Par7& p7, 1.460 + CrossCallReturn* answer) { 1.461 + XCALL_GEN_PARAMS_OBJ(7, call_params); 1.462 + XCALL_GEN_COPY_PARAM(1, call_params); 1.463 + XCALL_GEN_COPY_PARAM(2, call_params); 1.464 + XCALL_GEN_COPY_PARAM(3, call_params); 1.465 + XCALL_GEN_COPY_PARAM(4, call_params); 1.466 + XCALL_GEN_COPY_PARAM(5, call_params); 1.467 + XCALL_GEN_COPY_PARAM(6, call_params); 1.468 + XCALL_GEN_COPY_PARAM(7, call_params); 1.469 + 1.470 + ResultCode result = ipc_provider.DoCall(call_params, answer); 1.471 + 1.472 + if (SBOX_ERROR_CHANNEL_ERROR != result) { 1.473 + XCALL_GEN_UPDATE_PARAM(1, call_params); 1.474 + XCALL_GEN_UPDATE_PARAM(2, call_params); 1.475 + XCALL_GEN_UPDATE_PARAM(3, call_params); 1.476 + XCALL_GEN_UPDATE_PARAM(4, call_params); 1.477 + XCALL_GEN_UPDATE_PARAM(5, call_params); 1.478 + XCALL_GEN_UPDATE_PARAM(6, call_params); 1.479 + XCALL_GEN_UPDATE_PARAM(7, call_params); 1.480 + XCALL_GEN_FREE_CHANNEL(); 1.481 + } 1.482 + return result; 1.483 +} 1.484 +} // namespace sandbox 1.485 + 1.486 +#endif // SANDBOX_SRC_CROSSCALL_CLIENT_H__