#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "mojo/core/ipcz_driver/transport.h"
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/functional/overloaded.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/core/ipcz_driver/data_pipe.h"
#include "mojo/core/ipcz_driver/invitation.h"
#include "mojo/core/ipcz_driver/object.h"
#include "mojo/core/ipcz_driver/shared_buffer.h"
#include "mojo/core/ipcz_driver/transmissible_platform_handle.h"
#include "mojo/core/ipcz_driver/wrapped_platform_handle.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/ipcz/include/ipcz/ipcz.h"
#if BUILDFLAG(IS_WIN)
#include "mojo/public/cpp/platform/platform_handle_security_util_win.h"
#endif
namespace mojo::core::ipcz_driver {
namespace {
#if BUILDFLAG(IS_WIN)
enum HandleOwner : uint8_t {
kSender,
kRecipient,
};
using HandleData = uint64_t;
HandleData HandleToData(HANDLE handle) {
return static_cast<HandleData>(reinterpret_cast<uintptr_t>(handle));
}
HANDLE DataToHandle(HandleData data) {
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(data));
}
#endif
struct IPCZ_ALIGN(8) ObjectHeader { … };
struct IPCZ_ALIGN(8) TransportHeader { … };
#if BUILDFLAG(IS_WIN)
bool EncodeHandle(PlatformHandle& handle,
const base::Process& remote_process,
HandleOwner handle_owner,
HandleData& out_handle_data,
bool is_remote_process_untrusted) {
CHECK(handle.is_valid());
if (handle_owner == HandleOwner::kSender) {
out_handle_data = HandleToData(handle.ReleaseHandle());
return true;
}
DCHECK_EQ(handle_owner, HandleOwner::kRecipient);
DCHECK(remote_process.IsValid());
#if BUILDFLAG(IS_WIN)
if (is_remote_process_untrusted) {
DcheckIfFileHandleIsUnsafe(handle.GetHandle().get());
}
#endif
HANDLE new_handle;
if (!::DuplicateHandle(::GetCurrentProcess(), handle.ReleaseHandle(),
remote_process.Handle(), &new_handle, 0, FALSE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) {
return false;
}
out_handle_data = HandleToData(new_handle);
return true;
}
PlatformHandle DecodeHandle(HandleData data,
const base::Process& remote_process,
HandleOwner handle_owner,
Transport& from_transport) {
const HANDLE handle = DataToHandle(data);
if (handle_owner == HandleOwner::kRecipient) {
if (from_transport.destination_type() != Transport::kBroker &&
!from_transport.is_peer_trusted() && !remote_process.is_current()) {
return PlatformHandle();
}
return PlatformHandle(base::win::ScopedHandle(handle));
}
if (!remote_process.IsValid()) {
return PlatformHandle();
}
HANDLE local_dupe = INVALID_HANDLE_VALUE;
::DuplicateHandle(remote_process.Handle(), handle, ::GetCurrentProcess(),
&local_dupe, 0, FALSE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
return PlatformHandle(base::win::ScopedHandle(local_dupe));
}
#endif
scoped_refptr<base::SingleThreadTaskRunner>& GetIOTaskRunnerStorage() { … }
}
Transport::Transport(EndpointTypes endpoint_types,
PlatformChannelEndpoint endpoint,
base::Process remote_process,
bool is_remote_process_untrusted)
: … { … }
scoped_refptr<Transport> Transport::Create(EndpointTypes endpoint_types,
PlatformChannelEndpoint endpoint,
base::Process remote_process,
bool is_remote_process_untrusted) { … }
std::pair<scoped_refptr<Transport>, scoped_refptr<Transport>>
Transport::CreatePair(EndpointType first_type, EndpointType second_type) { … }
Transport::~Transport() { … }
void Transport::SetIOTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> runner) { … }
const scoped_refptr<base::SingleThreadTaskRunner>&
Transport::GetIOTaskRunner() { … }
void Transport::OverrideIOTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) { … }
void Transport::ReportBadActivity(const std::string& error_message) { … }
bool Transport::Activate(IpczHandle transport,
IpczTransportActivityHandler activity_handler) { … }
bool Transport::Deactivate() { … }
bool Transport::Transmit(base::span<const uint8_t> data,
base::span<const IpczDriverHandle> handles) { … }
IpczResult Transport::SerializeObject(ObjectBase& object,
void* data,
size_t* num_bytes,
IpczDriverHandle* handles,
size_t* num_handles) { … }
IpczResult Transport::DeserializeObject(
base::span<const uint8_t> bytes,
base::span<const IpczDriverHandle> handles,
scoped_refptr<ObjectBase>& object) { … }
void Transport::Close() { … }
bool Transport::IsSerializable() const { … }
bool Transport::GetSerializedDimensions(Transport& transmitter,
size_t& num_bytes,
size_t& num_handles) { … }
bool Transport::Serialize(Transport& transmitter,
base::span<uint8_t> data,
base::span<PlatformHandle> handles) { … }
scoped_refptr<Transport> Transport::Deserialize(
Transport& from_transport,
base::span<const uint8_t> data,
base::span<PlatformHandle> handles) { … }
bool Transport::IsIpczTransport() const { … }
void Transport::OnChannelMessage(const void* payload,
size_t payload_size,
std::vector<PlatformHandle> handles) { … }
void Transport::OnChannelError(Channel::Error error) { … }
void Transport::OnChannelDestroyed() { … }
bool Transport::CanTransmitHandles() const { … }
bool Transport::ShouldSerializeProcessHandle(Transport& transmitter) const { … }
Transport::PendingTransmission::PendingTransmission() = default;
Transport::PendingTransmission::PendingTransmission(PendingTransmission&&) =
default;
Transport::PendingTransmission& Transport::PendingTransmission::operator=(
PendingTransmission&&) = default;
Transport::PendingTransmission::~PendingTransmission() = default;
}