security/sandbox/win/src/crosscall_client.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_CLIENT_H_
michael@0 6 #define SANDBOX_SRC_CROSSCALL_CLIENT_H_
michael@0 7
michael@0 8 #include "sandbox/win/src/crosscall_params.h"
michael@0 9 #include "sandbox/win/src/sandbox.h"
michael@0 10
michael@0 11 // This header defines the CrossCall(..) family of templated functions
michael@0 12 // Their purpose is to simulate the syntax of regular call but to generate
michael@0 13 // and IPC from the client-side.
michael@0 14 //
michael@0 15 // The basic pattern is to
michael@0 16 // 1) use template argument deduction to compute the size of each
michael@0 17 // parameter and the appropriate copy method
michael@0 18 // 2) pack the parameters in the appropriate ActualCallParams< > object
michael@0 19 // 3) call the IPC interface IPCProvider::DoCall( )
michael@0 20 //
michael@0 21 // The general interface of CrossCall is:
michael@0 22 // ResultCode CrossCall(IPCProvider& ipc_provider,
michael@0 23 // uint32 tag,
michael@0 24 // const Par1& p1, const Par2& p2,...pn
michael@0 25 // CrossCallReturn* answer)
michael@0 26 //
michael@0 27 // where:
michael@0 28 // ipc_provider: is a specific implementation of the ipc transport see
michael@0 29 // sharedmem_ipc_server.h for an example.
michael@0 30 // tag : is the unique id for this IPC call. Is used to route the call to
michael@0 31 // the appropriate service.
michael@0 32 // p1, p2,.. pn : The input parameters of the IPC. Use only simple types
michael@0 33 // and wide strings (can add support for others).
michael@0 34 // answer : If the IPC was successful. The server-side answer is here. The
michael@0 35 // interpretation of the answer is private to client and server.
michael@0 36 //
michael@0 37 // The return value is ALL_OK if the IPC was delivered to the server, other
michael@0 38 // return codes indicate that the IPC transport failed to deliver it.
michael@0 39 namespace sandbox {
michael@0 40
michael@0 41 // this is the assumed channel size. This can be overridden in a given
michael@0 42 // IPC implementation.
michael@0 43 const uint32 kIPCChannelSize = 1024;
michael@0 44
michael@0 45 // The copy helper uses templates to deduce the appropriate copy function to
michael@0 46 // copy the input parameters in the buffer that is going to be send across the
michael@0 47 // IPC. These template facility can be made more sophisticated as need arises.
michael@0 48
michael@0 49 // The default copy helper. It catches the general case where no other
michael@0 50 // specialized template matches better. We set the type to ULONG_TYPE, so this
michael@0 51 // only works with objects whose size is 32 bits.
michael@0 52 template<typename T>
michael@0 53 class CopyHelper {
michael@0 54 public:
michael@0 55 CopyHelper(const T& t) : t_(t) {}
michael@0 56
michael@0 57 // Returns the pointer to the start of the input.
michael@0 58 const void* GetStart() const {
michael@0 59 return &t_;
michael@0 60 }
michael@0 61
michael@0 62 // Update the stored value with the value in the buffer. This is not
michael@0 63 // supported for this type.
michael@0 64 bool Update(void* buffer) {
michael@0 65 // Not supported;
michael@0 66 return true;
michael@0 67 }
michael@0 68
michael@0 69 // Returns the size of the input in bytes.
michael@0 70 uint32 GetSize() const {
michael@0 71 return sizeof(T);
michael@0 72 }
michael@0 73
michael@0 74 // Returns true if the current type is used as an In or InOut parameter.
michael@0 75 bool IsInOut() {
michael@0 76 return false;
michael@0 77 }
michael@0 78
michael@0 79 // Returns this object's type.
michael@0 80 ArgType GetType() {
michael@0 81 COMPILE_ASSERT(sizeof(T) == sizeof(uint32), need_specialization);
michael@0 82 return ULONG_TYPE;
michael@0 83 }
michael@0 84
michael@0 85 private:
michael@0 86 const T& t_;
michael@0 87 };
michael@0 88
michael@0 89 // This copy helper template specialization if for the void pointer
michael@0 90 // case both 32 and 64 bit.
michael@0 91 template<>
michael@0 92 class CopyHelper<void*> {
michael@0 93 public:
michael@0 94 CopyHelper(void* t) : t_(t) {}
michael@0 95
michael@0 96 // Returns the pointer to the start of the input.
michael@0 97 const void* GetStart() const {
michael@0 98 return &t_;
michael@0 99 }
michael@0 100
michael@0 101 // Update the stored value with the value in the buffer. This is not
michael@0 102 // supported for this type.
michael@0 103 bool Update(void* buffer) {
michael@0 104 // Not supported;
michael@0 105 return true;
michael@0 106 }
michael@0 107
michael@0 108 // Returns the size of the input in bytes.
michael@0 109 uint32 GetSize() const {
michael@0 110 return sizeof(t_);
michael@0 111 }
michael@0 112
michael@0 113 // Returns true if the current type is used as an In or InOut parameter.
michael@0 114 bool IsInOut() {
michael@0 115 return false;
michael@0 116 }
michael@0 117
michael@0 118 // Returns this object's type.
michael@0 119 ArgType GetType() {
michael@0 120 return VOIDPTR_TYPE;
michael@0 121 }
michael@0 122
michael@0 123 private:
michael@0 124 const void* t_;
michael@0 125 };
michael@0 126
michael@0 127 // This copy helper template specialization catches the cases where the
michael@0 128 // parameter is a pointer to a string.
michael@0 129 template<>
michael@0 130 class CopyHelper<const wchar_t*> {
michael@0 131 public:
michael@0 132 CopyHelper(const wchar_t* t)
michael@0 133 : t_(t) {
michael@0 134 }
michael@0 135
michael@0 136 // Returns the pointer to the start of the string.
michael@0 137 const void* GetStart() const {
michael@0 138 return t_;
michael@0 139 }
michael@0 140
michael@0 141 // Update the stored value with the value in the buffer. This is not
michael@0 142 // supported for this type.
michael@0 143 bool Update(void* buffer) {
michael@0 144 // Not supported;
michael@0 145 return true;
michael@0 146 }
michael@0 147
michael@0 148 // Returns the size of the string in bytes. We define a NULL string to
michael@0 149 // be of zero length.
michael@0 150 uint32 GetSize() const {
michael@0 151 __try {
michael@0 152 return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0]));
michael@0 153 }
michael@0 154 __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 155 return kuint32max;
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 // Returns true if the current type is used as an In or InOut parameter.
michael@0 160 bool IsInOut() {
michael@0 161 return false;
michael@0 162 }
michael@0 163
michael@0 164 ArgType GetType() {
michael@0 165 return WCHAR_TYPE;
michael@0 166 }
michael@0 167
michael@0 168 private:
michael@0 169 // We provide our not very optimized version of wcslen(), since we don't
michael@0 170 // want to risk having the linker use the version in the CRT since the CRT
michael@0 171 // might not be present when we do an early IPC call.
michael@0 172 static size_t __cdecl StringLength(const wchar_t* wcs) {
michael@0 173 const wchar_t *eos = wcs;
michael@0 174 while (*eos++);
michael@0 175 return static_cast<size_t>(eos - wcs - 1);
michael@0 176 }
michael@0 177
michael@0 178 const wchar_t* t_;
michael@0 179 };
michael@0 180
michael@0 181 // Specialization for non-const strings. We just reuse the implementation of the
michael@0 182 // const string specialization.
michael@0 183 template<>
michael@0 184 class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
michael@0 185 public:
michael@0 186 typedef CopyHelper<const wchar_t*> Base;
michael@0 187 CopyHelper(wchar_t* t) : Base(t) {}
michael@0 188
michael@0 189 const void* GetStart() const {
michael@0 190 return Base::GetStart();
michael@0 191 }
michael@0 192
michael@0 193 bool Update(void* buffer) {
michael@0 194 return Base::Update(buffer);
michael@0 195 }
michael@0 196
michael@0 197 uint32 GetSize() const {
michael@0 198 return Base::GetSize();
michael@0 199 }
michael@0 200
michael@0 201 bool IsInOut() {
michael@0 202 return Base::IsInOut();
michael@0 203 }
michael@0 204
michael@0 205 ArgType GetType() {
michael@0 206 return Base::GetType();
michael@0 207 }
michael@0 208 };
michael@0 209
michael@0 210 // Specialization for wchar_t arrays strings. We just reuse the implementation
michael@0 211 // of the const string specialization.
michael@0 212 template<size_t n>
michael@0 213 class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
michael@0 214 public:
michael@0 215 typedef const wchar_t array[n];
michael@0 216 typedef CopyHelper<const wchar_t*> Base;
michael@0 217 CopyHelper(array t) : Base(t) {}
michael@0 218
michael@0 219 const void* GetStart() const {
michael@0 220 return Base::GetStart();
michael@0 221 }
michael@0 222
michael@0 223 bool Update(void* buffer) {
michael@0 224 return Base::Update(buffer);
michael@0 225 }
michael@0 226
michael@0 227 uint32 GetSize() const {
michael@0 228 return Base::GetSize();
michael@0 229 }
michael@0 230
michael@0 231 bool IsInOut() {
michael@0 232 return Base::IsInOut();
michael@0 233 }
michael@0 234
michael@0 235 ArgType GetType() {
michael@0 236 return Base::GetType();
michael@0 237 }
michael@0 238 };
michael@0 239
michael@0 240 // Generic encapsulation class containing a pointer to a buffer and the
michael@0 241 // size of the buffer. It is used by the IPC to be able to pass in/out
michael@0 242 // parameters.
michael@0 243 class InOutCountedBuffer : public CountedBuffer {
michael@0 244 public:
michael@0 245 InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {}
michael@0 246 };
michael@0 247
michael@0 248 // This copy helper template specialization catches the cases where the
michael@0 249 // parameter is a an input/output buffer.
michael@0 250 template<>
michael@0 251 class CopyHelper<InOutCountedBuffer> {
michael@0 252 public:
michael@0 253 CopyHelper(const InOutCountedBuffer t) : t_(t) {}
michael@0 254
michael@0 255 // Returns the pointer to the start of the string.
michael@0 256 const void* GetStart() const {
michael@0 257 return t_.Buffer();
michael@0 258 }
michael@0 259
michael@0 260 // Updates the buffer with the value from the new buffer in parameter.
michael@0 261 bool Update(void* buffer) {
michael@0 262 // We are touching user memory, this has to be done from inside a try
michael@0 263 // except.
michael@0 264 __try {
michael@0 265 memcpy(t_.Buffer(), buffer, t_.Size());
michael@0 266 }
michael@0 267 __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 268 return false;
michael@0 269 }
michael@0 270 return true;
michael@0 271 }
michael@0 272
michael@0 273 // Returns the size of the string in bytes. We define a NULL string to
michael@0 274 // be of zero length.
michael@0 275 uint32 GetSize() const {
michael@0 276 return t_.Size();
michael@0 277 }
michael@0 278
michael@0 279 // Returns true if the current type is used as an In or InOut parameter.
michael@0 280 bool IsInOut() {
michael@0 281 return true;
michael@0 282 }
michael@0 283
michael@0 284 ArgType GetType() {
michael@0 285 return INOUTPTR_TYPE;
michael@0 286 }
michael@0 287
michael@0 288 private:
michael@0 289 const InOutCountedBuffer t_;
michael@0 290 };
michael@0 291
michael@0 292 // The following two macros make it less error prone the generation
michael@0 293 // of CrossCall functions with ever more input parameters.
michael@0 294
michael@0 295 #define XCALL_GEN_PARAMS_OBJ(num, params) \
michael@0 296 typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
michael@0 297 void* raw_mem = ipc_provider.GetBuffer(); \
michael@0 298 if (NULL == raw_mem) \
michael@0 299 return SBOX_ERROR_NO_SPACE; \
michael@0 300 ActualParams* params = new(raw_mem) ActualParams(tag);
michael@0 301
michael@0 302 #define XCALL_GEN_COPY_PARAM(num, params) \
michael@0 303 COMPILE_ASSERT(kMaxIpcParams >= num, too_many_parameters); \
michael@0 304 CopyHelper<Par##num> ch##num(p##num); \
michael@0 305 if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
michael@0 306 ch##num.IsInOut(), ch##num.GetType())) \
michael@0 307 return SBOX_ERROR_NO_SPACE;
michael@0 308
michael@0 309 #define XCALL_GEN_UPDATE_PARAM(num, params) \
michael@0 310 if (!ch##num.Update(params->GetParamPtr(num-1))) {\
michael@0 311 ipc_provider.FreeBuffer(raw_mem); \
michael@0 312 return SBOX_ERROR_BAD_PARAMS; \
michael@0 313 }
michael@0 314
michael@0 315 #define XCALL_GEN_FREE_CHANNEL() \
michael@0 316 ipc_provider.FreeBuffer(raw_mem);
michael@0 317
michael@0 318 // CrossCall template with one input parameter
michael@0 319 template <typename IPCProvider, typename Par1>
michael@0 320 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 321 CrossCallReturn* answer) {
michael@0 322 XCALL_GEN_PARAMS_OBJ(1, call_params);
michael@0 323 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 324
michael@0 325 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 326
michael@0 327 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 328 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 329 XCALL_GEN_FREE_CHANNEL();
michael@0 330 }
michael@0 331
michael@0 332 return result;
michael@0 333 }
michael@0 334
michael@0 335 // CrossCall template with two input parameters.
michael@0 336 template <typename IPCProvider, typename Par1, typename Par2>
michael@0 337 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 338 const Par2& p2, CrossCallReturn* answer) {
michael@0 339 XCALL_GEN_PARAMS_OBJ(2, call_params);
michael@0 340 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 341 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 342
michael@0 343 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 344
michael@0 345 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 346 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 347 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 348 XCALL_GEN_FREE_CHANNEL();
michael@0 349 }
michael@0 350 return result;
michael@0 351 }
michael@0 352
michael@0 353 // CrossCall template with three input parameters.
michael@0 354 template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
michael@0 355 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 356 const Par2& p2, const Par3& p3, CrossCallReturn* answer) {
michael@0 357 XCALL_GEN_PARAMS_OBJ(3, call_params);
michael@0 358 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 359 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 360 XCALL_GEN_COPY_PARAM(3, call_params);
michael@0 361
michael@0 362 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 363
michael@0 364 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 365 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 366 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 367 XCALL_GEN_UPDATE_PARAM(3, call_params);
michael@0 368 XCALL_GEN_FREE_CHANNEL();
michael@0 369 }
michael@0 370 return result;
michael@0 371 }
michael@0 372
michael@0 373 // CrossCall template with four input parameters.
michael@0 374 template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
michael@0 375 typename Par4>
michael@0 376 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 377 const Par2& p2, const Par3& p3, const Par4& p4,
michael@0 378 CrossCallReturn* answer) {
michael@0 379 XCALL_GEN_PARAMS_OBJ(4, call_params);
michael@0 380 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 381 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 382 XCALL_GEN_COPY_PARAM(3, call_params);
michael@0 383 XCALL_GEN_COPY_PARAM(4, call_params);
michael@0 384
michael@0 385 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 386
michael@0 387 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 388 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 389 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 390 XCALL_GEN_UPDATE_PARAM(3, call_params);
michael@0 391 XCALL_GEN_UPDATE_PARAM(4, call_params);
michael@0 392 XCALL_GEN_FREE_CHANNEL();
michael@0 393 }
michael@0 394 return result;
michael@0 395 }
michael@0 396
michael@0 397 // CrossCall template with five input parameters.
michael@0 398 template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
michael@0 399 typename Par4, typename Par5>
michael@0 400 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 401 const Par2& p2, const Par3& p3, const Par4& p4,
michael@0 402 const Par5& p5, CrossCallReturn* answer) {
michael@0 403 XCALL_GEN_PARAMS_OBJ(5, call_params);
michael@0 404 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 405 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 406 XCALL_GEN_COPY_PARAM(3, call_params);
michael@0 407 XCALL_GEN_COPY_PARAM(4, call_params);
michael@0 408 XCALL_GEN_COPY_PARAM(5, call_params);
michael@0 409
michael@0 410 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 411
michael@0 412 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 413 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 414 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 415 XCALL_GEN_UPDATE_PARAM(3, call_params);
michael@0 416 XCALL_GEN_UPDATE_PARAM(4, call_params);
michael@0 417 XCALL_GEN_UPDATE_PARAM(5, call_params);
michael@0 418 XCALL_GEN_FREE_CHANNEL();
michael@0 419 }
michael@0 420 return result;
michael@0 421 }
michael@0 422
michael@0 423 // CrossCall template with six input parameters.
michael@0 424 template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
michael@0 425 typename Par4, typename Par5, typename Par6>
michael@0 426 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 427 const Par2& p2, const Par3& p3, const Par4& p4,
michael@0 428 const Par5& p5, const Par6& p6, CrossCallReturn* answer) {
michael@0 429 XCALL_GEN_PARAMS_OBJ(6, call_params);
michael@0 430 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 431 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 432 XCALL_GEN_COPY_PARAM(3, call_params);
michael@0 433 XCALL_GEN_COPY_PARAM(4, call_params);
michael@0 434 XCALL_GEN_COPY_PARAM(5, call_params);
michael@0 435 XCALL_GEN_COPY_PARAM(6, call_params);
michael@0 436
michael@0 437 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 438
michael@0 439 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 440 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 441 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 442 XCALL_GEN_UPDATE_PARAM(3, call_params);
michael@0 443 XCALL_GEN_UPDATE_PARAM(4, call_params);
michael@0 444 XCALL_GEN_UPDATE_PARAM(5, call_params);
michael@0 445 XCALL_GEN_UPDATE_PARAM(6, call_params);
michael@0 446 XCALL_GEN_FREE_CHANNEL();
michael@0 447 }
michael@0 448 return result;
michael@0 449 }
michael@0 450
michael@0 451 // CrossCall template with seven input parameters.
michael@0 452 template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
michael@0 453 typename Par4, typename Par5, typename Par6, typename Par7>
michael@0 454 ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
michael@0 455 const Par2& p2, const Par3& p3, const Par4& p4,
michael@0 456 const Par5& p5, const Par6& p6, const Par7& p7,
michael@0 457 CrossCallReturn* answer) {
michael@0 458 XCALL_GEN_PARAMS_OBJ(7, call_params);
michael@0 459 XCALL_GEN_COPY_PARAM(1, call_params);
michael@0 460 XCALL_GEN_COPY_PARAM(2, call_params);
michael@0 461 XCALL_GEN_COPY_PARAM(3, call_params);
michael@0 462 XCALL_GEN_COPY_PARAM(4, call_params);
michael@0 463 XCALL_GEN_COPY_PARAM(5, call_params);
michael@0 464 XCALL_GEN_COPY_PARAM(6, call_params);
michael@0 465 XCALL_GEN_COPY_PARAM(7, call_params);
michael@0 466
michael@0 467 ResultCode result = ipc_provider.DoCall(call_params, answer);
michael@0 468
michael@0 469 if (SBOX_ERROR_CHANNEL_ERROR != result) {
michael@0 470 XCALL_GEN_UPDATE_PARAM(1, call_params);
michael@0 471 XCALL_GEN_UPDATE_PARAM(2, call_params);
michael@0 472 XCALL_GEN_UPDATE_PARAM(3, call_params);
michael@0 473 XCALL_GEN_UPDATE_PARAM(4, call_params);
michael@0 474 XCALL_GEN_UPDATE_PARAM(5, call_params);
michael@0 475 XCALL_GEN_UPDATE_PARAM(6, call_params);
michael@0 476 XCALL_GEN_UPDATE_PARAM(7, call_params);
michael@0 477 XCALL_GEN_FREE_CHANNEL();
michael@0 478 }
michael@0 479 return result;
michael@0 480 }
michael@0 481 } // namespace sandbox
michael@0 482
michael@0 483 #endif // SANDBOX_SRC_CROSSCALL_CLIENT_H__

mercurial