1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_CORE_IPCZ_DRIVER_TRANSPORT_H_
#define MOJO_CORE_IPCZ_DRIVER_TRANSPORT_H_
#include <cstddef>
#include <cstdint>
#include <utility>
#include "base/check.h"
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/process/process.h"
#include "base/synchronization/lock.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/core/channel.h"
#include "mojo/core/ipcz_driver/object.h"
#include "mojo/core/system_impl_export.h"
#include "mojo/public/c/system/invitation.h"
#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "third_party/ipcz/include/ipcz/ipcz.h"
namespace mojo::core::ipcz_driver {
// An ipcz driver transport implementation backed by a Channel object.
class MOJO_SYSTEM_IMPL_EXPORT Transport : public Object<Transport>,
public Channel::Delegate {
public:
// Enumerates the type of node at local endpoint of a Transport object.
enum EndpointType : uint32_t {
kBroker,
kNonBroker,
// For ValidateEnum().
kMinValue = kBroker,
kMaxValue = kNonBroker,
};
// Is the remote process trusted, only tracked on Windows. Not directly
// sent over the wire.
enum class ProcessTrust : uint32_t {
#if BUILDFLAG(IS_WIN)
// Default to kTrusted. TODO(crbug.com/414392683) - invert this.
kTrusted,
kUntrusted,
#else
kUntracked,
#endif
};
struct EndpointTypes {
EndpointType source;
EndpointType destination;
};
Transport(EndpointTypes endpoint_types,
PlatformChannelEndpoint endpoint,
base::Process remote_process,
ProcessTrust remote_process_trust);
// Static helper that is slightly more readable due to better type deduction
// than MakeRefCounted<T>.
static scoped_refptr<Transport> Create(
EndpointTypes endpoint_types,
PlatformChannelEndpoint endpoint,
base::Process remote_process = base::Process(),
ProcessTrust remote_process_trust = ProcessTrust{});
static std::pair<scoped_refptr<Transport>, scoped_refptr<Transport>>
CreatePair(EndpointType first_type, EndpointType second_type);
// Accessors for a global TaskRunner to use for Transport I/O.
static void SetIOTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> runner);
static const scoped_refptr<base::SingleThreadTaskRunner>& GetIOTaskRunner();
static constexpr Type object_type() { return kTransport; }
EndpointType source_type() const { return endpoint_types_.source; }
EndpointType destination_type() const { return endpoint_types_.destination; }
const base::Process& remote_process() const { return remote_process_; }
// Provides a handle to the remote process on the other end of this transport.
// If this is called, it must be before the Transport is activated.
void set_remote_process(base::Process process) {
DCHECK(!remote_process_.IsValid());
remote_process_ = std::move(process);
}
void set_leak_channel_on_shutdown(bool leak) {
leak_channel_on_shutdown_ = leak;
}
void set_is_peer_trusted(bool trusted) { is_peer_trusted_ = trusted; }
bool is_peer_trusted() const { return is_peer_trusted_; }
void set_is_trusted_by_peer(bool trusted) { is_trusted_by_peer_ = trusted; }
bool is_trusted_by_peer() const { return is_trusted_by_peer_; }
ProcessTrust remote_process_trust() const { return remote_process_trust_; }
void SetErrorHandler(MojoProcessErrorHandler handler, uintptr_t context) {
error_handler_ = handler;
error_handler_context_ = context;
}
// Overrides the IO task runner used to monitor this transport for IO. Unless
// this is called, all Transports use the global IO task runner by default.
void OverrideIOTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Takes ownership of the Transport's underlying channel endpoint, effectively
// invalidating the transport. May only be called on a Transport which has not
// yet been activated, and only when the channel endpoint is not a server.
PlatformChannelEndpoint TakeEndpoint() {
return std::move(inactive_endpoint_);
}
// Handles reports of bad activity from ipcz, resulting from parcel rejection
// by the application.
void ReportBadActivity(const std::string& error_message);
// Activates this transport by creating and starting the underlying Channel
// instance.
bool Activate(IpczHandle transport,
IpczTransportActivityHandler activity_handler);
// Deactives this transport, release and calling ShutDown() on the underlying
// Channel. Channel shutdown is asynchronous and will conclude with an
// OnChannelDestroyed() invocation on this Transport.
bool Deactivate();
// Transmits `data` and `handles` over the underlying Channel. All handles in
// `handles` must reference TransmissibleHandle instances with an underlying
// handle the Channel can transmit out-of-band from `data`.
bool Transmit(base::span<const uint8_t> data,
base::span<const IpczDriverHandle> handles);
// Attempts to serialize `object` for eventual transmission over this
// Transport. This essentially implements the mojo-ipcz driver's Serialize()
// API and behaves according to its specification. Upon success, `object` may
// be invalidated.
IpczResult SerializeObject(ObjectBase& object,
void* data,
size_t* num_bytes,
IpczDriverHandle* handles,
size_t* num_handles);
// Deserializes a new driver object from `bytes` and `handles` received over
// this Transport.
IpczResult DeserializeObject(base::span<const uint8_t> bytes,
base::span<const IpczDriverHandle> handles,
scoped_refptr<ObjectBase>& object);
// Object:
void Close() override;
bool IsSerializable() const override;
bool GetSerializedDimensions(Transport& transmitter,
size_t& num_bytes,
size_t& num_handles) override;
bool Serialize(Transport& transmitter,
base::span<uint8_t> data,
base::span<PlatformHandle> handles) override;
static scoped_refptr<Transport> Deserialize(
Transport& from_transport,
base::span<const uint8_t> data,
base::span<PlatformHandle> handles);
// Channel::Delegate:
bool IsIpczTransport() const override;
void OnChannelMessage(const void* payload,
size_t payload_size,
std::vector<PlatformHandle> handles,
scoped_refptr<ipcz_driver::Envelope> envelope) override;
void OnChannelError(Channel::Error error) override;
void OnChannelDestroyed() override;
// Allow tests to nerf serialized handles to validate recipient behavior.
static size_t FirstHandleOffsetForTesting();
private:
struct PendingTransmission {
PendingTransmission();
PendingTransmission(PendingTransmission&&);
PendingTransmission& operator=(PendingTransmission&&);
~PendingTransmission();
std::vector<uint8_t> bytes;
std::vector<PlatformHandle> handles;
};
~Transport() override;
bool CanTransmitHandles() const;
// Indicates whether this transport should serialize its remote process handle
// along with its endpoint handle being serialized for transmission over
// `transmitter`. This must only be true if we have a valid remote process
// handle and `transmitter` goes to a broker. Always false on non-Windows
// platforms.
bool ShouldSerializeProcessHandle(Transport& transmitter) const;
const EndpointTypes endpoint_types_;
base::Process remote_process_;
MojoProcessErrorHandler error_handler_ = nullptr;
uintptr_t error_handler_context_ = 0;
bool leak_channel_on_shutdown_ = false;
// Indicates whether the remote transport endpoint is "trusted" by this
// endpoint. In practice this means we will accept pre-duplicated handles from
// the remote process on Windows. This bit is ignored if the remote endpoint
// is a broker, since brokers are implicitly trusted; and it's currently
// meaningless on platforms other than Windows.
bool is_peer_trusted_ = false;
// Indicates whether this endpoint is "trusted" by the remote endpoint.
// In practice this means the remote endpoint will accept pre-duplicated
// handles from us on Windows. This bit is ignored if the local endpoint is a
// broker, since brokers are implicitly trusted; and it's currently
// meaningless on platforms other than Windows.
bool is_trusted_by_peer_ = false;
// Indicates whether the remote process is "untrusted" in Mojo parlance,
// meaning this Transport restricts what kinds of objects can be transferred
// from this end (kTrusted or kUntrusted on Windows, kUntracked elsewhere.)
const ProcessTrust remote_process_trust_;
// The channel endpoint which will be used by this Transport to construct and
// start its underlying Channel instance once activated. Not guarded by a lock
// since it must not accessed beyond activation, where thread safety becomes a
// factor.
PlatformChannelEndpoint inactive_endpoint_;
base::Lock lock_;
scoped_refptr<Channel> channel_ GUARDED_BY(lock_);
// Transmissions prior to activation must be queued, as the Channel is not
// created until then. Queued messages are stored here. Once the Transport has
// been activated, this is no longer used.
std::vector<PendingTransmission> pending_transmissions_ GUARDED_BY(lock_);
// NOTE: Channel does not retain a reference to its Delegate (this Transport,
// in our case) and it may call back into us from any thread as long as it's
// still alive. So we retain a self-reference on behalf of the Channel and
// release it only once notified of the Channel's destruction.
//
// TODO(crbug.com/40058840): Refactor Channel so that this is
// unnecessary, once the non-ipcz Mojo implementation is phased out.
scoped_refptr<Transport> self_reference_for_channel_ GUARDED_BY(lock_);
// The IO task runner used by this Transport to watch for incoming I/O events.
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_{
GetIOTaskRunner()};
// These fields are not guarded by locks, since they're only set prior to
// activation and remain constant throughout the remainder of this object's
// lifetime.
IpczHandle ipcz_transport_ = IPCZ_INVALID_HANDLE;
IpczTransportActivityHandler activity_handler_ = nullptr;
};
} // namespace mojo::core::ipcz_driver
#endif // MOJO_CORE_IPCZ_DRIVER_TRANSPORT_H_
|