// Copyright 2015 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 IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_ #define IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_ #include #include #include #include "base/gtest_prod_util.h" #include "base/mac/scoped_mach_port.h" #include "base/macros.h" #include "base/memory/scoped_vector.h" #include "base/process/port_provider_mac.h" #include "base/synchronization/lock.h" #include "ipc/attachment_broker_privileged.h" #include "ipc/ipc_export.h" #include "ipc/mach_port_attachment_mac.h" namespace base { class PortProvider; } // namespace base namespace IPC { // This class is a concrete subclass of AttachmentBrokerPrivileged for the // OSX platform. // // An example of the typical process by which a Mach port gets brokered. // Definitions: // 1. Let there be three processes P1, U2, U3. P1 is privileged. // 2. U2 wants to send a Mach port M2 to U3. If this port is inserted into P1, // it will be called M1. If it is inserted into U3, it will be called M3. // 3. name() returns a serializable representation of a Mach port that can be // passed over chrome IPC. // 4. pid() returns the process id of a process. // // Process: // 1. U2 sends a AttachmentBrokerMsg_DuplicateMachPort message to P1. The // message contains name(M2), and pid(U3). // 2. P1 extracts M2 into its own namespace, making M1. // 3. P1 makes a new Mach port R in U3. // 4. P1 sends a mach_msg with M1 to R. // 5. P1 sends name(R) to U3. // 6. U3 retrieves the queued message from R. The kernel automatically // translates M1 into the namespace of U3, making M3. // // The logic of this class is a little bit more complex becauese any or all of // P1, U2 and U3 may be the same, and depending on the exact configuration, // the creation of R may not be necessary. // // For the rest of this file, and the corresponding implementation file, R will // be called the "intermediate Mach port" and M3 the "final Mach port". class IPC_EXPORT AttachmentBrokerPrivilegedMac : public AttachmentBrokerPrivileged, public base::PortProvider::Observer { public: explicit AttachmentBrokerPrivilegedMac(base::PortProvider* port_provider); ~AttachmentBrokerPrivilegedMac() override; // IPC::AttachmentBroker overrides. bool SendAttachmentToProcess( const scoped_refptr& attachment, base::ProcessId destination_process) override; void DeregisterCommunicationChannel(Endpoint* endpoint) override; // IPC::Listener overrides. bool OnMessageReceived(const Message& message) override; // base::PortProvider::Observer override. void OnReceivedTaskPort(base::ProcessHandle process) override; private: FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight); FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice); FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights); using MachPortWireFormat = internal::MachPortAttachmentMac::WireFormat; // Contains all the information necessary to broker an attachment into a // destination process. The only thing that prevents an AttachmentPrecusor // from being immediately processed is if |port_provider_| does not yet have a // task port for |pid|. class IPC_EXPORT AttachmentPrecursor { public: AttachmentPrecursor(const base::ProcessId& pid, base::mac::ScopedMachSendRight port_to_insert, const BrokerableAttachment::AttachmentId& id); ~AttachmentPrecursor(); // Caller takes ownership of |port_|. base::mac::ScopedMachSendRight TakePort(); base::ProcessId pid() const { return pid_; } const BrokerableAttachment::AttachmentId id() const { return id_; } private: // The pid of the destination process. const base::ProcessId pid_; // The final Mach port, as per definition at the top of this file. base::mac::ScopedMachSendRight port_; // The id of the attachment. const BrokerableAttachment::AttachmentId id_; DISALLOW_COPY_AND_ASSIGN(AttachmentPrecursor); }; // Contains all the information necessary to extract a send right and create // an AttachmentPrecursor. The only thing that prevents an AttachmentExtractor // from being immediately processed is if |port_provider_| does not yet have a // task port for |source_pid|. class IPC_EXPORT AttachmentExtractor { public: AttachmentExtractor(const base::ProcessId& source_pid, const base::ProcessId& dest_pid, mach_port_name_t port, const BrokerableAttachment::AttachmentId& id); ~AttachmentExtractor(); base::ProcessId source_pid() const { return source_pid_; } base::ProcessId dest_pid() const { return dest_pid_; } mach_port_name_t port() const { return port_to_extract_; } const BrokerableAttachment::AttachmentId id() const { return id_; } private: const base::ProcessId source_pid_; const base::ProcessId dest_pid_; mach_port_name_t port_to_extract_; const BrokerableAttachment::AttachmentId id_; }; // IPC message handlers. void OnDuplicateMachPort(const Message& message); // Duplicates the Mach port referenced from |wire_format| from // |source_process| into |wire_format|'s destination process. MachPortWireFormat DuplicateMachPort(const MachPortWireFormat& wire_format, base::ProcessId source_process); // Extracts a copy of the send right to |named_right| from |task_port|. // Returns MACH_PORT_NULL on error. base::mac::ScopedMachSendRight ExtractNamedRight( mach_port_t task_port, mach_port_name_t named_right); // Copies an existing |wire_format|, but substitutes in a different mach port. MachPortWireFormat CopyWireFormat(const MachPortWireFormat& wire_format, uint32_t mach_port); // |wire_format.destination_process| must be this process. // |wire_format.mach_port| must be the final Mach port. // Consumes a reference to |wire_format.mach_port|, as ownership is implicitly // passed to the consumer of the Chrome IPC message. // Makes an attachment, queues it, and notifies the observers. void RoutePrecursorToSelf(AttachmentPrecursor* precursor); // |wire_format.destination_process| must be another process. // |wire_format.mach_port| must be the intermediate Mach port. // Ownership of |wire_format.mach_port| is implicitly passed to the process // that receives the Chrome IPC message. // Returns |false| on irrecoverable error. bool RouteWireFormatToAnother(const MachPortWireFormat& wire_format); // Atempts to broker all precursors whose destination is |pid|. Has no effect // if |port_provider_| does not have the task port for |pid|. void SendPrecursorsForProcess(base::ProcessId pid); // Brokers a single precursor into the task represented by |task_port|. // Returns |false| on irrecoverable error. bool SendPrecursor(AttachmentPrecursor* precursor, mach_port_t task_port); // Add a precursor to |precursors_|. Takes ownership of |port|. void AddPrecursor(base::ProcessId pid, base::mac::ScopedMachSendRight port, const BrokerableAttachment::AttachmentId& id); // Atempts to process all extractors whose source is |pid|. Has no effect // if |port_provider_| does not have the task port for |pid|. void ProcessExtractorsForProcess(base::ProcessId pid); // Processes a single extractor whose source pid is represented by // |task_port|. void ProcessExtractor(AttachmentExtractor* extractor, mach_port_t task_port); // Add an extractor to |extractors_|. void AddExtractor(base::ProcessId source_pid, base::ProcessId dest_pid, mach_port_name_t port, const BrokerableAttachment::AttachmentId& id); // The port provider must live at least as long as the AttachmentBroker. base::PortProvider* port_provider_; // For each ProcessId, a vector of precursors that are waiting to be // sent. std::map*> precursors_; base::Lock precursors_lock_; // For each ProcessId, a vector of extractors that are waiting to be // processed. std::map*> extractors_; base::Lock extractors_lock_; DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMac); }; } // namespace IPC #endif // IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_