chromium/sandbox/win/src/crosscall_server.h

// Copyright 2012 The Chromium Authors
// 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_SERVER_H_
#define SANDBOX_WIN_SRC_CROSSCALL_SERVER_H_

#include <stdint.h>

#include <string>
#include <vector>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "sandbox/win/src/crosscall_params.h"
#include "sandbox/win/src/ipc_tags.h"

// This is the IPC server interface for CrossCall: The  IPC for the Sandbox
// On the server, CrossCall needs two things:
// 1) threads: Or better said, someone to provide them, that is what the
//             ThreadPool is for. These thread(s) are
//             the ones that will actually execute the IPC data retrieval.
//
// 2) a dispatcher: This interface represents the way to route and process
//                  an  IPC call given the  IPC tag.
//
// The other class included here CrossCallParamsEx is the server side version
// of the CrossCallParams class of /sandbox/crosscall_params.h The difference
// is that the sever version is paranoid about the correctness of the IPC
// message and will do all sorts of verifications.
//
// A general diagram of the interaction is as follows:
//
//                                 ------------
//                                 |          |
//  ThreadPool<-------(1)Register--|  IPC     |
//      |                          | Implemen |
//      |                          | -tation  |
//     (2)                         |          |  OnMessage
//     IPC fired --callback ------>|          |--(3)---> Dispatcher
//                                 |          |
//                                 ------------
//
//  The  IPC implementation sits as a middleman between the handling of the
//  specifics of scheduling a thread to service the  IPC and the multiple
//  entities that can potentially serve each particular IPC.
namespace sandbox {

class InterceptionManager;

// Models the server-side of the original input parameters.
// Provides IPC buffer validation and it is capable of reading the parameters
// out of the IPC buffer.
class CrossCallParamsEx : public CrossCallParams {
 public:
  // Factory constructor. Pass an IPCbuffer (and buffer size) that contains a
  // pending IPCcall. This constructor will:
  // 1) validate the IPC buffer. returns nullptr is the IPCbuffer is malformed.
  // 2) make a copy of the IPCbuffer (parameter capture)
  static CrossCallParamsEx* CreateFromBuffer(void* buffer_base,
                                             uint32_t buffer_size,
                                             uint32_t* output_size);

  CrossCallParamsEx(const CrossCallParamsEx&) = delete;
  CrossCallParamsEx& operator=(const CrossCallParamsEx&) = delete;

  // Provides IPCinput parameter raw access:
  // index : the parameter to read; 0 is the first parameter
  // returns nullptr if the parameter is non-existent. If it exists it also
  // returns the size in *size
  void* GetRawParameter(uint32_t index, uint32_t* size, ArgType* type);

  // Gets a parameter that is four bytes in size.
  // Returns false if the parameter does not exist or is not 32 bits wide.
  bool GetParameter32(uint32_t index, uint32_t* param);

  // Gets a parameter that is void pointer in size.
  // Returns false if the parameter does not exist or is not void pointer sized.
  bool GetParameterVoidPtr(uint32_t index, void** param);

  // Gets a parameter that is a string. Returns false if the parameter does not
  // exist.
  bool GetParameterStr(uint32_t index, std::wstring* string);

  // Gets a parameter that is an in/out buffer. Returns false is the parameter
  // does not exist or if the size of the actual parameter is not equal to the
  // expected size.
  bool GetParameterPtr(uint32_t index, uint32_t expected_size, void** pointer);

  // Frees the memory associated with the IPC parameters.
  static void operator delete(void* raw_memory) throw();

 private:
  // Only the factory method CreateFromBuffer can construct these objects.
  CrossCallParamsEx();

  ParamInfo param_info_[1];
};

// Simple helper function that sets the members of CrossCallReturn
// to the proper state to signal a basic error.
void SetCallError(ResultCode error, CrossCallReturn* call_return);

// Sets the internal status of call_return to signify the that IPC call
// completed successfully.
void SetCallSuccess(CrossCallReturn* call_return);

// Represents the client process that initiated the IPC which boils down to the
// process handle and the job object handle that contains the client process.
struct ClientInfo {
  HANDLE process;
  DWORD process_id;
};

// All IPC-related information to be passed to the IPC handler.
struct IPCInfo {
  IpcTag ipc_tag;
  raw_ptr<const ClientInfo> client_info;
  CrossCallReturn return_info;
};

// This structure identifies IPC signatures.
struct IPCParams {
  IpcTag ipc_tag;
  ArgType args[kMaxIpcParams];

  bool Matches(IPCParams* other) const {
    return !memcmp(this, other, sizeof(*other));
  }
};

// Models an entity that can process an IPC message or it can route to another
// one that could handle it. When an IPC arrives the IPC implementation will:
// 1) call OnMessageReady() with the tag of the pending IPC. If the dispatcher
//    returns nullptr it means that it cannot handle this IPC but if it returns
//    non-null, it must be the pointer to a dispatcher that can handle it.
// 2) When the  IPC finally obtains a valid Dispatcher the IPC
//    implementation creates a CrossCallParamsEx from the raw IPC buffer.
// 3) It calls the returned callback, with the IPC info and arguments.
class [[clang::lto_visibility_public]] Dispatcher {
 public:
  // Called from the  IPC implementation to handle a specific IPC message.
  typedef bool (Dispatcher::*CallbackGeneric)();
  typedef bool (Dispatcher::*Callback0)(IPCInfo* ipc);
  typedef bool (Dispatcher::*Callback1)(IPCInfo* ipc, void* p1);
  typedef bool (Dispatcher::*Callback2)(IPCInfo* ipc, void* p1, void* p2);
  typedef bool (Dispatcher::*Callback3)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3);
  typedef bool (Dispatcher::*Callback4)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4);
  typedef bool (Dispatcher::*Callback5)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4,
                                        void* p5);
  typedef bool (Dispatcher::*Callback6)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4,
                                        void* p5,
                                        void* p6);
  typedef bool (Dispatcher::*Callback7)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4,
                                        void* p5,
                                        void* p6,
                                        void* p7);
  typedef bool (Dispatcher::*Callback8)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4,
                                        void* p5,
                                        void* p6,
                                        void* p7,
                                        void* p8);
  typedef bool (Dispatcher::*Callback9)(IPCInfo* ipc,
                                        void* p1,
                                        void* p2,
                                        void* p3,
                                        void* p4,
                                        void* p5,
                                        void* p6,
                                        void* p7,
                                        void* p8,
                                        void* p9);

  // Called from the  IPC implementation when an  IPC message is ready override
  // on a derived class to handle a set of  IPC messages. Return nullptr if your
  // subclass does not handle the message or return the pointer to the subclass
  // that can handle it.
  virtual Dispatcher* OnMessageReady(IPCParams* ipc, CallbackGeneric* callback);

  // Called when a target proces is created, to setup the interceptions related
  // with the given service (IPC).
  virtual bool SetupService(InterceptionManager* manager, IpcTag service) = 0;

  Dispatcher();
  virtual ~Dispatcher();

 protected:
  // Structure that defines an IPC Call with all the parameters and the handler.
  struct IPCCall {
    IPCParams params;
    CallbackGeneric callback;
  };

  // List of IPC Calls supported by the class.
  std::vector<IPCCall> ipc_calls_;
};

}  // namespace sandbox

#endif  // SANDBOX_WIN_SRC_CROSSCALL_SERVER_H_