123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_
- #define SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_
- #include <stddef.h>
- #include <stdint.h>
- #include "base/compiler_specific.h"
- #include "sandbox/win/src/crosscall_params.h"
- #include "sandbox/win/src/sandbox.h"
- // This header defines the CrossCall(..) family of templated functions
- // Their purpose is to simulate the syntax of regular call but to generate
- // and IPC from the client-side.
- //
- // The basic pattern is to
- // 1) use template argument deduction to compute the size of each
- // parameter and the appropriate copy method
- // 2) pack the parameters in the appropriate ActualCallParams< > object
- // 3) call the IPC interface IPCProvider::DoCall( )
- //
- // The general interface of CrossCall is:
- // ResultCode CrossCall(IPCProvider& ipc_provider,
- // uint32_t tag,
- // const Par1& p1, const Par2& p2,...pn
- // CrossCallReturn* answer)
- //
- // where:
- // ipc_provider: is a specific implementation of the ipc transport see
- // sharedmem_ipc_server.h for an example.
- // tag : is the unique id for this IPC call. Is used to route the call to
- // the appropriate service.
- // p1, p2,.. pn : The input parameters of the IPC. Use only simple types
- // and wide strings (can add support for others).
- // answer : If the IPC was successful. The server-side answer is here. The
- // interpretation of the answer is private to client and server.
- //
- // The return value is ALL_OK if the IPC was delivered to the server, other
- // return codes indicate that the IPC transport failed to deliver it.
- namespace sandbox {
- enum class IpcTag;
- // this is the assumed channel size. This can be overridden in a given
- // IPC implementation.
- const uint32_t kIPCChannelSize = 1024;
- // The copy helper uses templates to deduce the appropriate copy function to
- // copy the input parameters in the buffer that is going to be send across the
- // IPC. These template facility can be made more sophisticated as need arises.
- // The default copy helper. It catches the general case where no other
- // specialized template matches better. We set the type to UINT32_TYPE, so this
- // only works with objects whose size is 32 bits.
- template <typename T>
- class CopyHelper {
- public:
- explicit CopyHelper(const T& t) : t_(t) {}
- // Returns the pointer to the start of the input.
- const void* GetStart() const { return &t_; }
- // Update the stored value with the value in the buffer. This is not
- // supported for this type.
- bool Update(void* buffer) {
- // Not supported;
- return true;
- }
- // Returns the size of the input in bytes.
- uint32_t GetSize() const { return sizeof(T); }
- // Returns true if the current type is used as an In or InOut parameter.
- bool IsInOut() { return false; }
- // Returns this object's type.
- ArgType GetType() {
- static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
- return UINT32_TYPE;
- }
- private:
- const T& t_;
- };
- // This copy helper template specialization if for the void pointer
- // case both 32 and 64 bit.
- template <>
- class CopyHelper<void*> {
- public:
- explicit CopyHelper(void* t) : t_(t) {}
- // Returns the pointer to the start of the input.
- const void* GetStart() const { return &t_; }
- // Update the stored value with the value in the buffer. This is not
- // supported for this type.
- bool Update(void* buffer) {
- // Not supported;
- return true;
- }
- // Returns the size of the input in bytes.
- uint32_t GetSize() const { return sizeof(t_); }
- // Returns true if the current type is used as an In or InOut parameter.
- bool IsInOut() { return false; }
- // Returns this object's type.
- ArgType GetType() { return VOIDPTR_TYPE; }
- private:
- const void* t_;
- };
- // This copy helper template specialization catches the cases where the
- // parameter is a pointer to a string.
- template <>
- class CopyHelper<const wchar_t*> {
- public:
- explicit CopyHelper(const wchar_t* t) : t_(t) {}
- // Returns the pointer to the start of the string.
- const void* GetStart() const { return t_; }
- // Update the stored value with the value in the buffer. This is not
- // supported for this type.
- bool Update(void* buffer) {
- // Not supported;
- return true;
- }
- // Returns the size of the string in bytes. We define a nullptr string to
- // be of zero length.
- uint32_t GetSize() const {
- __try {
- return (!t_) ? 0
- : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- return UINT32_MAX;
- }
- }
- // Returns true if the current type is used as an In or InOut parameter.
- bool IsInOut() { return false; }
- ArgType GetType() { return WCHAR_TYPE; }
- private:
- // We provide our not very optimized version of wcslen(), since we don't
- // want to risk having the linker use the version in the CRT since the CRT
- // might not be present when we do an early IPC call.
- static size_t CDECL StringLength(const wchar_t* wcs) {
- const wchar_t* eos = wcs;
- while (*eos++)
- ;
- return static_cast<size_t>(eos - wcs - 1);
- }
- const wchar_t* t_;
- };
- // Specialization for non-const strings. We just reuse the implementation of the
- // const string specialization.
- template <>
- class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
- public:
- typedef CopyHelper<const wchar_t*> Base;
- explicit CopyHelper(wchar_t* t) : Base(t) {}
- const void* GetStart() const { return Base::GetStart(); }
- bool Update(void* buffer) { return Base::Update(buffer); }
- uint32_t GetSize() const { return Base::GetSize(); }
- bool IsInOut() { return Base::IsInOut(); }
- ArgType GetType() { return Base::GetType(); }
- };
- // Specialization for wchar_t arrays strings. We just reuse the implementation
- // of the const string specialization.
- template <size_t n>
- class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
- public:
- typedef const wchar_t array[n];
- typedef CopyHelper<const wchar_t*> Base;
- explicit CopyHelper(array t) : Base(t) {}
- const void* GetStart() const { return Base::GetStart(); }
- bool Update(void* buffer) { return Base::Update(buffer); }
- uint32_t GetSize() const { return Base::GetSize(); }
- bool IsInOut() { return Base::IsInOut(); }
- ArgType GetType() { return Base::GetType(); }
- };
- // Generic encapsulation class containing a pointer to a buffer and the
- // size of the buffer. It is used by the IPC to be able to pass in/out
- // parameters.
- class InOutCountedBuffer : public CountedBuffer {
- public:
- InOutCountedBuffer(void* buffer, uint32_t size)
- : CountedBuffer(buffer, size) {}
- };
- // This copy helper template specialization catches the cases where the
- // parameter is a an input/output buffer.
- template <>
- class CopyHelper<InOutCountedBuffer> {
- public:
- explicit CopyHelper(const InOutCountedBuffer t) : t_(t) {}
- // Returns the pointer to the start of the string.
- const void* GetStart() const { return t_.Buffer(); }
- // Updates the buffer with the value from the new buffer in parameter.
- bool Update(void* buffer) {
- // We are touching user memory, this has to be done from inside a try
- // except.
- __try {
- memcpy_wrapper(t_.Buffer(), buffer, t_.Size());
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- return false;
- }
- return true;
- }
- // Returns the size of the string in bytes. We define a nullptr string to
- // be of zero length.
- uint32_t GetSize() const { return t_.Size(); }
- // Returns true if the current type is used as an In or InOut parameter.
- bool IsInOut() { return true; }
- ArgType GetType() { return INOUTPTR_TYPE; }
- private:
- const InOutCountedBuffer t_;
- };
- // The following two macros make it less error prone the generation
- // of CrossCall functions with ever more input parameters.
- #define XCALL_GEN_PARAMS_OBJ(num, params) \
- typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
- void* raw_mem = ipc_provider.GetBuffer(); \
- if (!raw_mem) \
- return SBOX_ERROR_NO_SPACE; \
- ActualParams* params = new (raw_mem) ActualParams(tag);
- #define XCALL_GEN_COPY_PARAM(num, params) \
- static_assert(kMaxIpcParams >= num, "too many parameters"); \
- CopyHelper<Par##num> ch##num(p##num); \
- if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
- ch##num.IsInOut(), ch##num.GetType())) \
- return SBOX_ERROR_NO_SPACE;
- #define XCALL_GEN_UPDATE_PARAM(num, params) \
- if (!ch##num.Update(params->GetParamPtr(num - 1))) { \
- ipc_provider.FreeBuffer(raw_mem); \
- return SBOX_ERROR_BAD_PARAMS; \
- }
- #define XCALL_GEN_FREE_CHANNEL() ipc_provider.FreeBuffer(raw_mem);
- // CrossCall template with one input parameter
- template <typename IPCProvider, typename Par1>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(1, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with two input parameters.
- template <typename IPCProvider, typename Par1, typename Par2>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(2, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with three input parameters.
- template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- const Par3& p3,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(3, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- XCALL_GEN_COPY_PARAM(3, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_UPDATE_PARAM(3, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with four input parameters.
- template <typename IPCProvider,
- typename Par1,
- typename Par2,
- typename Par3,
- typename Par4>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- const Par3& p3,
- const Par4& p4,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(4, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- XCALL_GEN_COPY_PARAM(3, call_params);
- XCALL_GEN_COPY_PARAM(4, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_UPDATE_PARAM(3, call_params);
- XCALL_GEN_UPDATE_PARAM(4, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with five input parameters.
- template <typename IPCProvider,
- typename Par1,
- typename Par2,
- typename Par3,
- typename Par4,
- typename Par5>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- const Par3& p3,
- const Par4& p4,
- const Par5& p5,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(5, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- XCALL_GEN_COPY_PARAM(3, call_params);
- XCALL_GEN_COPY_PARAM(4, call_params);
- XCALL_GEN_COPY_PARAM(5, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_UPDATE_PARAM(3, call_params);
- XCALL_GEN_UPDATE_PARAM(4, call_params);
- XCALL_GEN_UPDATE_PARAM(5, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with six input parameters.
- template <typename IPCProvider,
- typename Par1,
- typename Par2,
- typename Par3,
- typename Par4,
- typename Par5,
- typename Par6>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- const Par3& p3,
- const Par4& p4,
- const Par5& p5,
- const Par6& p6,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(6, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- XCALL_GEN_COPY_PARAM(3, call_params);
- XCALL_GEN_COPY_PARAM(4, call_params);
- XCALL_GEN_COPY_PARAM(5, call_params);
- XCALL_GEN_COPY_PARAM(6, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_UPDATE_PARAM(3, call_params);
- XCALL_GEN_UPDATE_PARAM(4, call_params);
- XCALL_GEN_UPDATE_PARAM(5, call_params);
- XCALL_GEN_UPDATE_PARAM(6, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- // CrossCall template with seven input parameters.
- template <typename IPCProvider,
- typename Par1,
- typename Par2,
- typename Par3,
- typename Par4,
- typename Par5,
- typename Par6,
- typename Par7>
- ResultCode CrossCall(IPCProvider& ipc_provider,
- IpcTag tag,
- const Par1& p1,
- const Par2& p2,
- const Par3& p3,
- const Par4& p4,
- const Par5& p5,
- const Par6& p6,
- const Par7& p7,
- CrossCallReturn* answer) {
- XCALL_GEN_PARAMS_OBJ(7, call_params);
- XCALL_GEN_COPY_PARAM(1, call_params);
- XCALL_GEN_COPY_PARAM(2, call_params);
- XCALL_GEN_COPY_PARAM(3, call_params);
- XCALL_GEN_COPY_PARAM(4, call_params);
- XCALL_GEN_COPY_PARAM(5, call_params);
- XCALL_GEN_COPY_PARAM(6, call_params);
- XCALL_GEN_COPY_PARAM(7, call_params);
- ResultCode result = ipc_provider.DoCall(call_params, answer);
- if (SBOX_ERROR_CHANNEL_ERROR != result) {
- XCALL_GEN_UPDATE_PARAM(1, call_params);
- XCALL_GEN_UPDATE_PARAM(2, call_params);
- XCALL_GEN_UPDATE_PARAM(3, call_params);
- XCALL_GEN_UPDATE_PARAM(4, call_params);
- XCALL_GEN_UPDATE_PARAM(5, call_params);
- XCALL_GEN_UPDATE_PARAM(6, call_params);
- XCALL_GEN_UPDATE_PARAM(7, call_params);
- XCALL_GEN_FREE_CHANNEL();
- }
- return result;
- }
- } // namespace sandbox
- #endif // SANDBOX_WIN_SRC_CROSSCALL_CLIENT_H_
|