blob: 84d77f68d079fbc2c20d2496daf7156df0781104 [file] [log] [blame]
[email protected]456b0ea2012-03-30 19:57:221// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ipc/ipc_channel_nacl.h"
6
[email protected]4e8f0a762012-05-31 19:37:547#include <errno.h>
8#include <stddef.h>
tfarina10a5c062015-09-04 18:47:579#include <stdint.h>
[email protected]4e8f0a762012-05-31 19:37:5410#include <sys/types.h>
11
12#include <algorithm>
13
14#include "base/bind.h"
[email protected]456b0ea2012-03-30 19:57:2215#include "base/logging.h"
avi246998d82015-12-22 02:39:0416#include "base/macros.h"
skyostile687bdff2015-05-12 11:29:2117#include "base/single_thread_task_runner.h"
[email protected]4e8f0a762012-05-31 19:37:5418#include "base/synchronization/lock.h"
19#include "base/task_runner_util.h"
skyostile687bdff2015-05-12 11:29:2120#include "base/thread_task_runner_handle.h"
[email protected]4e8f0a762012-05-31 19:37:5421#include "base/threading/simple_thread.h"
[email protected]7e3d7522014-03-20 21:00:5022#include "ipc/ipc_listener.h"
[email protected]4e8f0a762012-05-31 19:37:5423#include "ipc/ipc_logging.h"
morrita4b5c28e22015-01-14 21:17:0624#include "ipc/ipc_message_attachment_set.h"
[email protected]18ff3c32013-06-05 23:37:1125#include "native_client/src/public/imc_syscalls.h"
26#include "native_client/src/public/imc_types.h"
[email protected]456b0ea2012-03-30 19:57:2227
28namespace IPC {
[email protected]ff79fa22012-07-10 17:26:0329
30struct MessageContents {
31 std::vector<char> data;
32 std::vector<int> fds;
33};
34
[email protected]4e8f0a762012-05-31 19:37:5435namespace {
36
[email protected]ff79fa22012-07-10 17:26:0337bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
[email protected]4e8f0a762012-05-31 19:37:5438 DCHECK(pipe >= 0);
[email protected]4e8f0a762012-05-31 19:37:5439 if (pipe < 0)
[email protected]ff79fa22012-07-10 17:26:0340 return false;
[email protected]4e8f0a762012-05-31 19:37:5441
[email protected]ff79fa22012-07-10 17:26:0342 contents->data.resize(Channel::kReadBufferSize);
yusukeseaa3c5bf2015-03-17 00:34:1343 contents->fds.resize(NACL_ABI_IMC_DESC_MAX);
[email protected]ff79fa22012-07-10 17:26:0344
[email protected]18ff3c32013-06-05 23:37:1145 NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() };
46 NaClAbiNaClImcMsgHdr msg = {
47 &iov, 1, &contents->fds[0], contents->fds.size()
48 };
[email protected]4e8f0a762012-05-31 19:37:5449
50 int bytes_read = imc_recvmsg(pipe, &msg, 0);
51
52 if (bytes_read <= 0) {
53 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
54 // due to error or for regular shutdown).
[email protected]ff79fa22012-07-10 17:26:0355 contents->data.clear();
56 contents->fds.clear();
57 return false;
[email protected]4e8f0a762012-05-31 19:37:5458 }
59 DCHECK(bytes_read);
[email protected]ff79fa22012-07-10 17:26:0360 // Resize the buffers down to the number of bytes and fds we actually read.
61 contents->data.resize(bytes_read);
62 contents->fds.resize(msg.desc_length);
63 return true;
[email protected]4e8f0a762012-05-31 19:37:5464}
65
66} // namespace
67
[email protected]2f60c9b2014-06-06 20:13:5168class ChannelNacl::ReaderThreadRunner
[email protected]4e8f0a762012-05-31 19:37:5469 : public base::DelegateSimpleThread::Delegate {
70 public:
71 // |pipe|: A file descriptor from which we will read using imc_recvmsg.
72 // |data_read_callback|: A callback we invoke (on the main thread) when we
[email protected]ff79fa22012-07-10 17:26:0373 // have read data.
[email protected]4e8f0a762012-05-31 19:37:5474 // |failure_callback|: A callback we invoke when we have a failure reading
75 // from |pipe|.
76 // |main_message_loop|: A proxy for the main thread, where we will invoke the
77 // above callbacks.
78 ReaderThreadRunner(
79 int pipe,
skyostile687bdff2015-05-12 11:29:2180 base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
81 base::Callback<void()> failure_callback,
82 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
[email protected]4e8f0a762012-05-31 19:37:5483
84 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
85 // until either we are told to quit or a read fails.
nickd60f7172015-04-23 16:42:4886 void Run() override;
[email protected]4e8f0a762012-05-31 19:37:5487
88 private:
89 int pipe_;
[email protected]ff79fa22012-07-10 17:26:0390 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_;
[email protected]4e8f0a762012-05-31 19:37:5491 base::Callback<void ()> failure_callback_;
skyostile687bdff2015-05-12 11:29:2192 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
[email protected]4e8f0a762012-05-31 19:37:5493
94 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
95};
96
[email protected]2f60c9b2014-06-06 20:13:5197ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
[email protected]4e8f0a762012-05-31 19:37:5498 int pipe,
skyostile687bdff2015-05-12 11:29:2199 base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
100 base::Callback<void()> failure_callback,
101 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
[email protected]4e8f0a762012-05-31 19:37:54102 : pipe_(pipe),
103 data_read_callback_(data_read_callback),
104 failure_callback_(failure_callback),
skyostile687bdff2015-05-12 11:29:21105 main_task_runner_(main_task_runner) {
[email protected]4e8f0a762012-05-31 19:37:54106}
107
[email protected]2f60c9b2014-06-06 20:13:51108void ChannelNacl::ReaderThreadRunner::Run() {
[email protected]4e8f0a762012-05-31 19:37:54109 while (true) {
[email protected]ff79fa22012-07-10 17:26:03110 scoped_ptr<MessageContents> msg_contents(new MessageContents);
111 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
112 if (success) {
skyostile687bdff2015-05-12 11:29:21113 main_task_runner_->PostTask(
114 FROM_HERE,
[email protected]d873f192013-01-23 02:20:35115 base::Bind(data_read_callback_, base::Passed(&msg_contents)));
[email protected]4e8f0a762012-05-31 19:37:54116 } else {
skyostile687bdff2015-05-12 11:29:21117 main_task_runner_->PostTask(FROM_HERE, failure_callback_);
[email protected]4e8f0a762012-05-31 19:37:54118 // Because the read failed, we know we're going to quit. Don't bother
119 // trying to read again.
120 return;
121 }
122 }
123}
[email protected]456b0ea2012-03-30 19:57:22124
[email protected]2f60c9b2014-06-06 20:13:51125ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
126 Mode mode,
erikchen30dc2812015-09-24 03:26:38127 Listener* listener)
[email protected]4e8f0a762012-05-31 19:37:54128 : ChannelReader(listener),
129 mode_(mode),
130 waiting_connect_(true),
131 pipe_(-1),
132 pipe_name_(channel_handle.name),
erikchen5708aae2015-09-14 17:45:12133 weak_ptr_factory_(this) {
[email protected]4e8f0a762012-05-31 19:37:54134 if (!CreatePipe(channel_handle)) {
135 // The pipe may have been closed already.
136 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
137 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name
138 << "\" in " << modestr << " mode";
139 }
[email protected]456b0ea2012-03-30 19:57:22140}
141
[email protected]2f60c9b2014-06-06 20:13:51142ChannelNacl::~ChannelNacl() {
erikchen53d919d2015-09-11 17:33:34143 CleanUp();
[email protected]456b0ea2012-03-30 19:57:22144 Close();
145}
146
[email protected]2f60c9b2014-06-06 20:13:51147base::ProcessId ChannelNacl::GetPeerPID() const {
[email protected]7e3d7522014-03-20 21:00:50148 // This shouldn't actually get used in the untrusted side of the proxy, and we
149 // don't have the real pid anyway.
150 return -1;
151}
152
[email protected]64860882014-08-04 23:44:17153base::ProcessId ChannelNacl::GetSelfPID() const {
154 return -1;
155}
156
[email protected]2f60c9b2014-06-06 20:13:51157bool ChannelNacl::Connect() {
[email protected]4e8f0a762012-05-31 19:37:54158 if (pipe_ == -1) {
[email protected]7e3d7522014-03-20 21:00:50159 DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
[email protected]4e8f0a762012-05-31 19:37:54160 return false;
161 }
162
[email protected]cf0e7ee2012-07-11 00:49:17163 // Note that Connect is called on the "Channel" thread (i.e., the same thread
164 // where Channel::Send will be called, and the same thread that should receive
165 // messages). The constructor might be invoked on another thread (see
166 // ChannelProxy for an example of that). Therefore, we must wait until Connect
skyostile687bdff2015-05-12 11:29:21167 // is called to decide which SingleThreadTaskRunner to pass to
168 // ReaderThreadRunner.
169 reader_thread_runner_.reset(new ReaderThreadRunner(
170 pipe_,
171 base::Bind(&ChannelNacl::DidRecvMsg, weak_ptr_factory_.GetWeakPtr()),
172 base::Bind(&ChannelNacl::ReadDidFail, weak_ptr_factory_.GetWeakPtr()),
173 base::ThreadTaskRunnerHandle::Get()));
[email protected]cf0e7ee2012-07-11 00:49:17174 reader_thread_.reset(
175 new base::DelegateSimpleThread(reader_thread_runner_.get(),
176 "ipc_channel_nacl reader thread"));
[email protected]4e8f0a762012-05-31 19:37:54177 reader_thread_->Start();
178 waiting_connect_ = false;
179 // If there were any messages queued before connection, send them.
180 ProcessOutgoingMessages();
skyostile687bdff2015-05-12 11:29:21181 base::ThreadTaskRunnerHandle::Get()->PostTask(
182 FROM_HERE, base::Bind(&ChannelNacl::CallOnChannelConnected,
183 weak_ptr_factory_.GetWeakPtr()));
[email protected]7e3d7522014-03-20 21:00:50184
[email protected]5ce038b2012-06-06 18:14:56185 return true;
[email protected]456b0ea2012-03-30 19:57:22186}
187
[email protected]2f60c9b2014-06-06 20:13:51188void ChannelNacl::Close() {
[email protected]4e8f0a762012-05-31 19:37:54189 // For now, we assume that at shutdown, the reader thread will be woken with
190 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
191 // might simply be killed with no chance to clean up anyway :-).
192 // If untrusted code tries to close the channel prior to shutdown, it's likely
193 // to hang.
194 // TODO(dmichael): Can we do anything smarter here to make sure the reader
195 // thread wakes up and quits?
196 reader_thread_->Join();
197 close(pipe_);
198 pipe_ = -1;
199 reader_thread_runner_.reset();
200 reader_thread_.reset();
201 read_queue_.clear();
202 output_queue_.clear();
[email protected]456b0ea2012-03-30 19:57:22203}
204
[email protected]2f60c9b2014-06-06 20:13:51205bool ChannelNacl::Send(Message* message) {
morrita81b17e02015-02-06 00:58:30206 DCHECK(!message->HasAttachments());
[email protected]4e8f0a762012-05-31 19:37:54207 DVLOG(2) << "sending message @" << message << " on channel @" << this
208 << " with type " << message->type();
209 scoped_ptr<Message> message_ptr(message);
210
211#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]19d3a3e2012-06-11 18:18:33212 Logging::GetInstance()->OnSendMessage(message_ptr.get(), "");
[email protected]4e8f0a762012-05-31 19:37:54213#endif // IPC_MESSAGE_LOG_ENABLED
214
yuhaoz9b8157d2015-08-18 22:21:35215 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
216 "ChannelNacl::Send",
217 message->header()->flags,
218 TRACE_EVENT_FLAG_FLOW_OUT);
[email protected]19d3a3e2012-06-11 18:18:33219 output_queue_.push_back(linked_ptr<Message>(message_ptr.release()));
[email protected]4e8f0a762012-05-31 19:37:54220 if (!waiting_connect_)
221 return ProcessOutgoingMessages();
222
223 return true;
[email protected]456b0ea2012-03-30 19:57:22224}
225
erikchen27aa7d82015-06-16 21:21:04226AttachmentBroker* ChannelNacl::GetAttachmentBroker() {
erikchen5708aae2015-09-14 17:45:12227 return nullptr;
erikchen27aa7d82015-06-16 21:21:04228}
229
[email protected]2f60c9b2014-06-06 20:13:51230void ChannelNacl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
[email protected]4e8f0a762012-05-31 19:37:54231 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
232 // the reader thread after Close is called. If so, we ignore it.
233 if (pipe_ == -1)
234 return;
235
[email protected]ff79fa22012-07-10 17:26:03236 linked_ptr<std::vector<char> > data(new std::vector<char>);
237 data->swap(contents->data);
238 read_queue_.push_back(data);
239
240 input_fds_.insert(input_fds_.end(),
241 contents->fds.begin(), contents->fds.end());
242 contents->fds.clear();
[email protected]dbbe276b2012-06-06 21:47:57243
244 // In POSIX, we would be told when there are bytes to read by implementing
245 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we
246 // instead know at this point because the reader thread posted some data to
247 // us.
248 ProcessIncomingMessages();
[email protected]456b0ea2012-03-30 19:57:22249}
250
[email protected]2f60c9b2014-06-06 20:13:51251void ChannelNacl::ReadDidFail() {
[email protected]4e8f0a762012-05-31 19:37:54252 Close();
[email protected]456b0ea2012-03-30 19:57:22253}
254
[email protected]2f60c9b2014-06-06 20:13:51255bool ChannelNacl::CreatePipe(
[email protected]4e8f0a762012-05-31 19:37:54256 const IPC::ChannelHandle& channel_handle) {
257 DCHECK(pipe_ == -1);
258
259 // There's one possible case in NaCl:
260 // 1) It's a channel wrapping a pipe that is given to us.
261 // We don't support these:
262 // 2) It's for a named channel.
263 // 3) It's for a client that we implement ourself.
264 // 4) It's the initial IPC channel.
265
266 if (channel_handle.socket.fd == -1) {
267 NOTIMPLEMENTED();
268 return false;
269 }
270 pipe_ = channel_handle.socket.fd;
271 return true;
[email protected]456b0ea2012-03-30 19:57:22272}
273
[email protected]2f60c9b2014-06-06 20:13:51274bool ChannelNacl::ProcessOutgoingMessages() {
[email protected]4e8f0a762012-05-31 19:37:54275 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
276 // no connection?
277 if (output_queue_.empty())
278 return true;
279
280 if (pipe_ == -1)
281 return false;
282
283 // Write out all the messages. The trusted implementation is guaranteed to not
284 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
285 while (!output_queue_.empty()) {
286 linked_ptr<Message> msg = output_queue_.front();
287 output_queue_.pop_front();
288
morrita4b5c28e22015-01-14 21:17:06289 int fds[MessageAttachmentSet::kMaxDescriptorsPerMessage];
erikchenae6d3212015-10-10 02:43:49290 const size_t num_fds =
291 msg->attachment_set()->num_non_brokerable_attachments();
morrita4b5c28e22015-01-14 21:17:06292 DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
293 msg->attachment_set()->PeekDescriptors(fds);
[email protected]ff79fa22012-07-10 17:26:03294
[email protected]18ff3c32013-06-05 23:37:11295 NaClAbiNaClImcMsgIoVec iov = {
296 const_cast<void*>(msg->data()), msg->size()
297 };
298 NaClAbiNaClImcMsgHdr msgh = { &iov, 1, fds, num_fds };
[email protected]4e8f0a762012-05-31 19:37:54299 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0);
300
[email protected]ff79fa22012-07-10 17:26:03301 DCHECK(bytes_written); // The trusted side shouldn't return 0.
[email protected]4e8f0a762012-05-31 19:37:54302 if (bytes_written < 0) {
303 // The trusted side should only ever give us an error of EPIPE. We
304 // should never be interrupted, nor should we get EAGAIN.
305 DCHECK(errno == EPIPE);
306 Close();
307 PLOG(ERROR) << "pipe_ error on "
308 << pipe_
309 << " Currently writing message of size: "
310 << msg->size();
311 return false;
[email protected]ff79fa22012-07-10 17:26:03312 } else {
erikchenae6d3212015-10-10 02:43:49313 msg->attachment_set()->CommitAllDescriptors();
[email protected]4e8f0a762012-05-31 19:37:54314 }
315
316 // Message sent OK!
317 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
318 << " on fd " << pipe_;
319 }
320 return true;
[email protected]456b0ea2012-03-30 19:57:22321}
322
[email protected]2f60c9b2014-06-06 20:13:51323void ChannelNacl::CallOnChannelConnected() {
324 listener()->OnChannelConnected(GetPeerPID());
[email protected]7e3d7522014-03-20 21:00:50325}
326
[email protected]2f60c9b2014-06-06 20:13:51327ChannelNacl::ReadState ChannelNacl::ReadData(
[email protected]4e8f0a762012-05-31 19:37:54328 char* buffer,
329 int buffer_len,
330 int* bytes_read) {
331 *bytes_read = 0;
332 if (pipe_ == -1)
333 return READ_FAILED;
334 if (read_queue_.empty())
335 return READ_PENDING;
336 while (!read_queue_.empty() && *bytes_read < buffer_len) {
337 linked_ptr<std::vector<char> > vec(read_queue_.front());
[email protected]74ca23f2012-09-24 04:49:10338 size_t bytes_to_read = buffer_len - *bytes_read;
[email protected]4e8f0a762012-05-31 19:37:54339 if (vec->size() <= bytes_to_read) {
340 // We can read and discard the entire vector.
341 std::copy(vec->begin(), vec->end(), buffer + *bytes_read);
342 *bytes_read += vec->size();
343 read_queue_.pop_front();
344 } else {
345 // Read all the bytes we can and discard them from the front of the
346 // vector. (This can be slowish, since erase has to move the back of the
347 // vector to the front, but it's hopefully a temporary hack and it keeps
348 // the code simple).
349 std::copy(vec->begin(), vec->begin() + bytes_to_read,
350 buffer + *bytes_read);
351 vec->erase(vec->begin(), vec->begin() + bytes_to_read);
352 *bytes_read += bytes_to_read;
353 }
354 }
355 return READ_SUCCEEDED;
[email protected]fe5d4062012-04-23 21:18:19356}
357
erikchende9412b82015-07-27 18:26:14358bool ChannelNacl::ShouldDispatchInputMessage(Message* msg) {
359 return true;
360}
361
362bool ChannelNacl::GetNonBrokeredAttachments(Message* msg) {
tfarina10a5c062015-09-04 18:47:57363 uint16_t header_fds = msg->header()->num_fds;
[email protected]ff79fa22012-07-10 17:26:03364 CHECK(header_fds == input_fds_.size());
365 if (header_fds == 0)
366 return true; // Nothing to do.
367
368 // The shenaniganery below with &foo.front() requires input_fds_ to have
369 // contiguous underlying storage (such as a simple array or a std::vector).
370 // This is why the header warns not to make input_fds_ a deque<>.
morrita4b5c28e22015-01-14 21:17:06371 msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds);
[email protected]ff79fa22012-07-10 17:26:03372 input_fds_.clear();
[email protected]4e8f0a762012-05-31 19:37:54373 return true;
[email protected]fe5d4062012-04-23 21:18:19374}
375
[email protected]2f60c9b2014-06-06 20:13:51376bool ChannelNacl::DidEmptyInputBuffers() {
[email protected]ff79fa22012-07-10 17:26:03377 // When the input data buffer is empty, the fds should be too.
378 return input_fds_.empty();
[email protected]fe5d4062012-04-23 21:18:19379}
380
[email protected]2f60c9b2014-06-06 20:13:51381void ChannelNacl::HandleInternalMessage(const Message& msg) {
[email protected]4e8f0a762012-05-31 19:37:54382 // The trusted side IPC::Channel should handle the "hello" handshake; we
383 // should not receive the "Hello" message.
384 NOTREACHED();
[email protected]456b0ea2012-03-30 19:57:22385}
386
erikchen3c175a32015-07-28 23:16:48387base::ProcessId ChannelNacl::GetSenderPID() {
388 // The untrusted side of the IPC::Channel should never have to worry about
389 // sender's process id.
390 return base::kNullProcessId;
391}
392
erikchen8c73f832015-07-30 22:26:08393bool ChannelNacl::IsAttachmentBrokerEndpoint() {
394 return is_attachment_broker_endpoint();
395}
396
[email protected]2f60c9b2014-06-06 20:13:51397// Channel's methods
[email protected]456b0ea2012-03-30 19:57:22398
[email protected]2f60c9b2014-06-06 20:13:51399// static
erikchen27aa7d82015-06-16 21:21:04400scoped_ptr<Channel> Channel::Create(const IPC::ChannelHandle& channel_handle,
401 Mode mode,
erikchen30dc2812015-09-24 03:26:38402 Listener* listener) {
403 return scoped_ptr<Channel>(new ChannelNacl(channel_handle, mode, listener));
[email protected]456b0ea2012-03-30 19:57:22404}
405
[email protected]456b0ea2012-03-30 19:57:22406} // namespace IPC