michael@0: // Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef SANDBOX_SRC_CROSSCALL_SERVER_H_ michael@0: #define SANDBOX_SRC_CROSSCALL_SERVER_H_ michael@0: michael@0: #include michael@0: #include michael@0: #include "base/basictypes.h" michael@0: #include "base/callback.h" michael@0: #include "sandbox/win/src/crosscall_params.h" michael@0: michael@0: // This is the IPC server interface for CrossCall: The IPC for the Sandbox michael@0: // On the server, CrossCall needs two things: michael@0: // 1) threads: Or better said, someone to provide them, that is what the michael@0: // ThreadProvider interface is defined for. These thread(s) are michael@0: // the ones that will actually execute the IPC data retrieval. michael@0: // michael@0: // 2) a dispatcher: This interface represents the way to route and process michael@0: // an IPC call given the IPC tag. michael@0: // michael@0: // The other class included here CrossCallParamsEx is the server side version michael@0: // of the CrossCallParams class of /sandbox/crosscall_params.h The difference michael@0: // is that the sever version is paranoid about the correctness of the IPC michael@0: // message and will do all sorts of verifications. michael@0: // michael@0: // A general diagram of the interaction is as follows: michael@0: // michael@0: // ------------ michael@0: // | | michael@0: // ThreadProvider <--(1)Register--| IPC | michael@0: // | | Implemen | michael@0: // | | -tation | michael@0: // (2) | | OnMessage michael@0: // IPC fired --callback ------>| |--(3)---> Dispatcher michael@0: // | | michael@0: // ------------ michael@0: // michael@0: // The IPC implementation sits as a middleman between the handling of the michael@0: // specifics of scheduling a thread to service the IPC and the multiple michael@0: // entities that can potentially serve each particular IPC. michael@0: namespace sandbox { michael@0: michael@0: class InterceptionManager; michael@0: michael@0: // This function signature is required as the callback when an IPC call fires. michael@0: // context: a user-defined pointer that was set using ThreadProvider michael@0: // reason: 0 if the callback was fired because of a timeout. michael@0: // 1 if the callback was fired because of an event. michael@0: typedef void (__stdcall * CrossCallIPCCallback)(void* context, michael@0: unsigned char reason); michael@0: michael@0: // ThreadProvider models a thread factory. The idea is to decouple thread michael@0: // creation and lifetime from the inner guts of the IPC. The contract is michael@0: // simple: michael@0: // - the IPC implementation calls RegisterWait with a waitable object that michael@0: // becomes signaled when an IPC arrives and needs to be serviced. michael@0: // - when the waitable object becomes signaled, the thread provider conjures michael@0: // a thread that calls the callback (CrossCallIPCCallback) function michael@0: // - the callback function tries its best not to block and return quickly michael@0: // and should not assume that the next callback will use the same thread michael@0: // - when the callback returns the ThreadProvider owns again the thread michael@0: // and can destroy it or keep it around. michael@0: class ThreadProvider { michael@0: public: michael@0: // Registers a waitable object with the thread provider. michael@0: // client: A number to associate with all the RegisterWait calls, typically michael@0: // this is the address of the caller object. This parameter cannot michael@0: // be zero. michael@0: // waitable_object : a kernel object that can be waited on michael@0: // callback: a function pointer which is the function that will be called michael@0: // when the waitable object fires michael@0: // context: a user-provider pointer that is passed back to the callback michael@0: // when its called michael@0: virtual bool RegisterWait(const void* client, HANDLE waitable_object, michael@0: CrossCallIPCCallback callback, michael@0: void* context) = 0; michael@0: michael@0: // Removes all the registrations done with the same cookie parameter. michael@0: // This frees internal thread pool resources. michael@0: virtual bool UnRegisterWaits(void* cookie) = 0; michael@0: virtual ~ThreadProvider() {} michael@0: }; michael@0: michael@0: // Models the server-side of the original input parameters. michael@0: // Provides IPC buffer validation and it is capable of reading the parameters michael@0: // out of the IPC buffer. michael@0: class CrossCallParamsEx : public CrossCallParams { michael@0: public: michael@0: // Factory constructor. Pass an IPCbuffer (and buffer size) that contains a michael@0: // pending IPCcall. This constructor will: michael@0: // 1) validate the IPC buffer. returns NULL is the IPCbuffer is malformed. michael@0: // 2) make a copy of the IPCbuffer (parameter capture) michael@0: static CrossCallParamsEx* CreateFromBuffer(void* buffer_base, michael@0: uint32 buffer_size, michael@0: uint32* output_size); michael@0: michael@0: // Provides IPCinput parameter raw access: michael@0: // index : the parameter to read; 0 is the first parameter michael@0: // returns NULL if the parameter is non-existent. If it exists it also michael@0: // returns the size in *size michael@0: void* GetRawParameter(uint32 index, uint32* size, ArgType* type); michael@0: michael@0: // Gets a parameter that is four bytes in size. michael@0: // Returns false if the parameter does not exist or is not 32 bits wide. michael@0: bool GetParameter32(uint32 index, uint32* param); michael@0: michael@0: // Gets a parameter that is void pointer in size. michael@0: // Returns false if the parameter does not exist or is not void pointer sized. michael@0: bool GetParameterVoidPtr(uint32 index, void** param); michael@0: michael@0: // Gets a parameter that is a string. Returns false if the parameter does not michael@0: // exist. michael@0: bool GetParameterStr(uint32 index, std::wstring* string); michael@0: michael@0: // Gets a parameter that is an in/out buffer. Returns false is the parameter michael@0: // does not exist or if the size of the actual parameter is not equal to the michael@0: // expected size. michael@0: bool GetParameterPtr(uint32 index, uint32 expected_size, void** pointer); michael@0: michael@0: // Frees the memory associated with the IPC parameters. michael@0: static void operator delete(void* raw_memory) throw(); michael@0: michael@0: private: michael@0: // Only the factory method CreateFromBuffer can construct these objects. michael@0: CrossCallParamsEx(); michael@0: michael@0: ParamInfo param_info_[1]; michael@0: DISALLOW_COPY_AND_ASSIGN(CrossCallParamsEx); michael@0: }; michael@0: michael@0: // Simple helper function that sets the members of CrossCallReturn michael@0: // to the proper state to signal a basic error. michael@0: void SetCallError(ResultCode error, CrossCallReturn* call_return); michael@0: michael@0: // Sets the internal status of call_return to signify the that IPC call michael@0: // completed successfully. michael@0: void SetCallSuccess(CrossCallReturn* call_return); michael@0: michael@0: // Represents the client process that initiated the IPC which boils down to the michael@0: // process handle and the job object handle that contains the client process. michael@0: struct ClientInfo { michael@0: HANDLE process; michael@0: HANDLE job_object; michael@0: DWORD process_id; michael@0: }; michael@0: michael@0: // All IPC-related information to be passed to the IPC handler. michael@0: struct IPCInfo { michael@0: int ipc_tag; michael@0: const ClientInfo* client_info; michael@0: CrossCallReturn return_info; michael@0: }; michael@0: michael@0: // This structure identifies IPC signatures. michael@0: struct IPCParams { michael@0: int ipc_tag; michael@0: ArgType args[kMaxIpcParams]; michael@0: michael@0: bool Matches(IPCParams* other) const { michael@0: return !memcmp(this, other, sizeof(*other)); michael@0: } michael@0: }; michael@0: michael@0: // Models an entity that can process an IPC message or it can route to another michael@0: // one that could handle it. When an IPC arrives the IPC implementation will: michael@0: // 1) call OnMessageReady() with the tag of the pending IPC. If the dispatcher michael@0: // returns NULL it means that it cannot handle this IPC but if it returns michael@0: // non-null, it must be the pointer to a dispatcher that can handle it. michael@0: // 2) When the IPC finally obtains a valid Dispatcher the IPC michael@0: // implementation creates a CrossCallParamsEx from the raw IPC buffer. michael@0: // 3) It calls the returned callback, with the IPC info and arguments. michael@0: class Dispatcher { michael@0: public: michael@0: // Called from the IPC implementation to handle a specific IPC message. michael@0: typedef bool (Dispatcher::*CallbackGeneric)(); michael@0: typedef bool (Dispatcher::*Callback0)(IPCInfo* ipc); michael@0: typedef bool (Dispatcher::*Callback1)(IPCInfo* ipc, void* p1); michael@0: typedef bool (Dispatcher::*Callback2)(IPCInfo* ipc, void* p1, void* p2); michael@0: typedef bool (Dispatcher::*Callback3)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3); michael@0: typedef bool (Dispatcher::*Callback4)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4); michael@0: typedef bool (Dispatcher::*Callback5)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4, void* p5); michael@0: typedef bool (Dispatcher::*Callback6)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4, void* p5, void* p6); michael@0: typedef bool (Dispatcher::*Callback7)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4, void* p5, void* p6, michael@0: void* p7); michael@0: typedef bool (Dispatcher::*Callback8)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4, void* p5, void* p6, michael@0: void* p7, void* p8); michael@0: typedef bool (Dispatcher::*Callback9)(IPCInfo* ipc, void* p1, void* p2, michael@0: void* p3, void* p4, void* p5, void* p6, michael@0: void* p7, void* p8, void* p9); michael@0: michael@0: // Called from the IPC implementation when an IPC message is ready override michael@0: // on a derived class to handle a set of IPC messages. Return NULL if your michael@0: // subclass does not handle the message or return the pointer to the subclass michael@0: // that can handle it. michael@0: virtual Dispatcher* OnMessageReady(IPCParams* ipc, CallbackGeneric* callback); michael@0: michael@0: // Called when a target proces is created, to setup the interceptions related michael@0: // with the given service (IPC). michael@0: virtual bool SetupService(InterceptionManager* manager, int service) = 0; michael@0: michael@0: virtual ~Dispatcher() {} michael@0: michael@0: protected: michael@0: // Structure that defines an IPC Call with all the parameters and the handler. michael@0: struct IPCCall { michael@0: IPCParams params; michael@0: CallbackGeneric callback; michael@0: }; michael@0: michael@0: // List of IPC Calls supported by the class. michael@0: std::vector ipc_calls_; michael@0: }; michael@0: michael@0: } // namespace sandbox michael@0: michael@0: #endif // SANDBOX_SRC_CROSSCALL_SERVER_H_