summaryrefslogtreecommitdiffstats
path: root/ipc/attachment_broker_privileged_mac.h
blob: 0393fe1d91aa1ad1e65a93500631aa96c093e606 (plain)
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
// 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 <mach/mach.h>
#include <stdint.h>

#include <map>

#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<IPC::BrokerableAttachment>& 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<base::ProcessId, ScopedVector<AttachmentPrecursor>*> precursors_;
  base::Lock precursors_lock_;

  // For each ProcessId, a vector of extractors that are waiting to be
  // processed.
  std::map<base::ProcessId, ScopedVector<AttachmentExtractor>*> extractors_;
  base::Lock extractors_lock_;

  DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMac);
};

}  // namespace IPC

#endif  // IPC_ATTACHMENT_BROKER_PRIVILEGED_MAC_H_