blob: 19a32891af1ab95f9393e2702f3082373f43fc4d [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>
[email protected]4e8f0a762012-05-31 19:37:549#include <sys/types.h>
10
11#include <algorithm>
12
13#include "base/bind.h"
[email protected]456b0ea2012-03-30 19:57:2214#include "base/logging.h"
skyostile687bdff2015-05-12 11:29:2115#include "base/single_thread_task_runner.h"
[email protected]4e8f0a762012-05-31 19:37:5416#include "base/synchronization/lock.h"
17#include "base/task_runner_util.h"
skyostile687bdff2015-05-12 11:29:2118#include "base/thread_task_runner_handle.h"
[email protected]4e8f0a762012-05-31 19:37:5419#include "base/threading/simple_thread.h"
[email protected]7e3d7522014-03-20 21:00:5020#include "ipc/ipc_listener.h"
[email protected]4e8f0a762012-05-31 19:37:5421#include "ipc/ipc_logging.h"
morrita4b5c28e22015-01-14 21:17:0622#include "ipc/ipc_message_attachment_set.h"
[email protected]18ff3c32013-06-05 23:37:1123#include "native_client/src/public/imc_syscalls.h"
24#include "native_client/src/public/imc_types.h"
[email protected]456b0ea2012-03-30 19:57:2225
26namespace IPC {
[email protected]ff79fa22012-07-10 17:26:0327
28struct MessageContents {
29 std::vector<char> data;
30 std::vector<int> fds;
31};
32
[email protected]4e8f0a762012-05-31 19:37:5433namespace {
34
[email protected]ff79fa22012-07-10 17:26:0335bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
[email protected]4e8f0a762012-05-31 19:37:5436 DCHECK(pipe >= 0);
[email protected]4e8f0a762012-05-31 19:37:5437 if (pipe < 0)
[email protected]ff79fa22012-07-10 17:26:0338 return false;
[email protected]4e8f0a762012-05-31 19:37:5439
[email protected]ff79fa22012-07-10 17:26:0340 contents->data.resize(Channel::kReadBufferSize);
yusukeseaa3c5bf2015-03-17 00:34:1341 contents->fds.resize(NACL_ABI_IMC_DESC_MAX);
[email protected]ff79fa22012-07-10 17:26:0342
[email protected]18ff3c32013-06-05 23:37:1143 NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() };
44 NaClAbiNaClImcMsgHdr msg = {
45 &iov, 1, &contents->fds[0], contents->fds.size()
46 };
[email protected]4e8f0a762012-05-31 19:37:5447
48 int bytes_read = imc_recvmsg(pipe, &msg, 0);
49
50 if (bytes_read <= 0) {
51 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
52 // due to error or for regular shutdown).
[email protected]ff79fa22012-07-10 17:26:0353 contents->data.clear();
54 contents->fds.clear();
55 return false;
[email protected]4e8f0a762012-05-31 19:37:5456 }
57 DCHECK(bytes_read);
[email protected]ff79fa22012-07-10 17:26:0358 // Resize the buffers down to the number of bytes and fds we actually read.
59 contents->data.resize(bytes_read);
60 contents->fds.resize(msg.desc_length);
61 return true;
[email protected]4e8f0a762012-05-31 19:37:5462}
63
64} // namespace
65
[email protected]2f60c9b2014-06-06 20:13:5166class ChannelNacl::ReaderThreadRunner
[email protected]4e8f0a762012-05-31 19:37:5467 : public base::DelegateSimpleThread::Delegate {
68 public:
69 // |pipe|: A file descriptor from which we will read using imc_recvmsg.
70 // |data_read_callback|: A callback we invoke (on the main thread) when we
[email protected]ff79fa22012-07-10 17:26:0371 // have read data.
[email protected]4e8f0a762012-05-31 19:37:5472 // |failure_callback|: A callback we invoke when we have a failure reading
73 // from |pipe|.
74 // |main_message_loop|: A proxy for the main thread, where we will invoke the
75 // above callbacks.
76 ReaderThreadRunner(
77 int pipe,
skyostile687bdff2015-05-12 11:29:2178 base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
79 base::Callback<void()> failure_callback,
80 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
[email protected]4e8f0a762012-05-31 19:37:5481
82 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
83 // until either we are told to quit or a read fails.
nickd60f7172015-04-23 16:42:4884 void Run() override;
[email protected]4e8f0a762012-05-31 19:37:5485
86 private:
87 int pipe_;
[email protected]ff79fa22012-07-10 17:26:0388 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_;
[email protected]4e8f0a762012-05-31 19:37:5489 base::Callback<void ()> failure_callback_;
skyostile687bdff2015-05-12 11:29:2190 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
[email protected]4e8f0a762012-05-31 19:37:5491
92 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
93};
94
[email protected]2f60c9b2014-06-06 20:13:5195ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
[email protected]4e8f0a762012-05-31 19:37:5496 int pipe,
skyostile687bdff2015-05-12 11:29:2197 base::Callback<void(scoped_ptr<MessageContents>)> data_read_callback,
98 base::Callback<void()> failure_callback,
99 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
[email protected]4e8f0a762012-05-31 19:37:54100 : pipe_(pipe),
101 data_read_callback_(data_read_callback),
102 failure_callback_(failure_callback),
skyostile687bdff2015-05-12 11:29:21103 main_task_runner_(main_task_runner) {
[email protected]4e8f0a762012-05-31 19:37:54104}
105
[email protected]2f60c9b2014-06-06 20:13:51106void ChannelNacl::ReaderThreadRunner::Run() {
[email protected]4e8f0a762012-05-31 19:37:54107 while (true) {
[email protected]ff79fa22012-07-10 17:26:03108 scoped_ptr<MessageContents> msg_contents(new MessageContents);
109 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
110 if (success) {
skyostile687bdff2015-05-12 11:29:21111 main_task_runner_->PostTask(
112 FROM_HERE,
[email protected]d873f192013-01-23 02:20:35113 base::Bind(data_read_callback_, base::Passed(&msg_contents)));
[email protected]4e8f0a762012-05-31 19:37:54114 } else {
skyostile687bdff2015-05-12 11:29:21115 main_task_runner_->PostTask(FROM_HERE, failure_callback_);
[email protected]4e8f0a762012-05-31 19:37:54116 // Because the read failed, we know we're going to quit. Don't bother
117 // trying to read again.
118 return;
119 }
120 }
121}
[email protected]456b0ea2012-03-30 19:57:22122
[email protected]2f60c9b2014-06-06 20:13:51123ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
124 Mode mode,
erikchen27aa7d82015-06-16 21:21:04125 Listener* listener,
126 AttachmentBroker* broker)
[email protected]4e8f0a762012-05-31 19:37:54127 : ChannelReader(listener),
128 mode_(mode),
129 waiting_connect_(true),
130 pipe_(-1),
131 pipe_name_(channel_handle.name),
erikchen27aa7d82015-06-16 21:21:04132 weak_ptr_factory_(this),
133 broker_(broker) {
[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() {
[email protected]456b0ea2012-03-30 19:57:22143 Close();
144}
145
[email protected]2f60c9b2014-06-06 20:13:51146base::ProcessId ChannelNacl::GetPeerPID() const {
[email protected]7e3d7522014-03-20 21:00:50147 // This shouldn't actually get used in the untrusted side of the proxy, and we
148 // don't have the real pid anyway.
149 return -1;
150}
151
[email protected]64860882014-08-04 23:44:17152base::ProcessId ChannelNacl::GetSelfPID() const {
153 return -1;
154}
155
[email protected]2f60c9b2014-06-06 20:13:51156bool ChannelNacl::Connect() {
[email protected]4e8f0a762012-05-31 19:37:54157 if (pipe_ == -1) {
[email protected]7e3d7522014-03-20 21:00:50158 DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
[email protected]4e8f0a762012-05-31 19:37:54159 return false;
160 }
161
[email protected]cf0e7ee2012-07-11 00:49:17162 // Note that Connect is called on the "Channel" thread (i.e., the same thread
163 // where Channel::Send will be called, and the same thread that should receive
164 // messages). The constructor might be invoked on another thread (see
165 // ChannelProxy for an example of that). Therefore, we must wait until Connect
skyostile687bdff2015-05-12 11:29:21166 // is called to decide which SingleThreadTaskRunner to pass to
167 // ReaderThreadRunner.
168 reader_thread_runner_.reset(new ReaderThreadRunner(
169 pipe_,
170 base::Bind(&ChannelNacl::DidRecvMsg, weak_ptr_factory_.GetWeakPtr()),
171 base::Bind(&ChannelNacl::ReadDidFail, weak_ptr_factory_.GetWeakPtr()),
172 base::ThreadTaskRunnerHandle::Get()));
[email protected]cf0e7ee2012-07-11 00:49:17173 reader_thread_.reset(
174 new base::DelegateSimpleThread(reader_thread_runner_.get(),
175 "ipc_channel_nacl reader thread"));
[email protected]4e8f0a762012-05-31 19:37:54176 reader_thread_->Start();
177 waiting_connect_ = false;
178 // If there were any messages queued before connection, send them.
179 ProcessOutgoingMessages();
skyostile687bdff2015-05-12 11:29:21180 base::ThreadTaskRunnerHandle::Get()->PostTask(
181 FROM_HERE, base::Bind(&ChannelNacl::CallOnChannelConnected,
182 weak_ptr_factory_.GetWeakPtr()));
[email protected]7e3d7522014-03-20 21:00:50183
[email protected]5ce038b2012-06-06 18:14:56184 return true;
[email protected]456b0ea2012-03-30 19:57:22185}
186
[email protected]2f60c9b2014-06-06 20:13:51187void ChannelNacl::Close() {
[email protected]4e8f0a762012-05-31 19:37:54188 // For now, we assume that at shutdown, the reader thread will be woken with
189 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
190 // might simply be killed with no chance to clean up anyway :-).
191 // If untrusted code tries to close the channel prior to shutdown, it's likely
192 // to hang.
193 // TODO(dmichael): Can we do anything smarter here to make sure the reader
194 // thread wakes up and quits?
195 reader_thread_->Join();
196 close(pipe_);
197 pipe_ = -1;
198 reader_thread_runner_.reset();
199 reader_thread_.reset();
200 read_queue_.clear();
201 output_queue_.clear();
[email protected]456b0ea2012-03-30 19:57:22202}
203
[email protected]2f60c9b2014-06-06 20:13:51204bool ChannelNacl::Send(Message* message) {
morrita81b17e02015-02-06 00:58:30205 DCHECK(!message->HasAttachments());
[email protected]4e8f0a762012-05-31 19:37:54206 DVLOG(2) << "sending message @" << message << " on channel @" << this
207 << " with type " << message->type();
208 scoped_ptr<Message> message_ptr(message);
209
210#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]19d3a3e2012-06-11 18:18:33211 Logging::GetInstance()->OnSendMessage(message_ptr.get(), "");
[email protected]4e8f0a762012-05-31 19:37:54212#endif // IPC_MESSAGE_LOG_ENABLED
213
[email protected]2c391df2012-09-18 03:41:29214 message->TraceMessageBegin();
[email protected]19d3a3e2012-06-11 18:18:33215 output_queue_.push_back(linked_ptr<Message>(message_ptr.release()));
[email protected]4e8f0a762012-05-31 19:37:54216 if (!waiting_connect_)
217 return ProcessOutgoingMessages();
218
219 return true;
[email protected]456b0ea2012-03-30 19:57:22220}
221
erikchen27aa7d82015-06-16 21:21:04222AttachmentBroker* ChannelNacl::GetAttachmentBroker() {
223 return broker_;
224}
225
[email protected]2f60c9b2014-06-06 20:13:51226void ChannelNacl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
[email protected]4e8f0a762012-05-31 19:37:54227 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
228 // the reader thread after Close is called. If so, we ignore it.
229 if (pipe_ == -1)
230 return;
231
[email protected]ff79fa22012-07-10 17:26:03232 linked_ptr<std::vector<char> > data(new std::vector<char>);
233 data->swap(contents->data);
234 read_queue_.push_back(data);
235
236 input_fds_.insert(input_fds_.end(),
237 contents->fds.begin(), contents->fds.end());
238 contents->fds.clear();
[email protected]dbbe276b2012-06-06 21:47:57239
240 // In POSIX, we would be told when there are bytes to read by implementing
241 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we
242 // instead know at this point because the reader thread posted some data to
243 // us.
244 ProcessIncomingMessages();
[email protected]456b0ea2012-03-30 19:57:22245}
246
[email protected]2f60c9b2014-06-06 20:13:51247void ChannelNacl::ReadDidFail() {
[email protected]4e8f0a762012-05-31 19:37:54248 Close();
[email protected]456b0ea2012-03-30 19:57:22249}
250
[email protected]2f60c9b2014-06-06 20:13:51251bool ChannelNacl::CreatePipe(
[email protected]4e8f0a762012-05-31 19:37:54252 const IPC::ChannelHandle& channel_handle) {
253 DCHECK(pipe_ == -1);
254
255 // There's one possible case in NaCl:
256 // 1) It's a channel wrapping a pipe that is given to us.
257 // We don't support these:
258 // 2) It's for a named channel.
259 // 3) It's for a client that we implement ourself.
260 // 4) It's the initial IPC channel.
261
262 if (channel_handle.socket.fd == -1) {
263 NOTIMPLEMENTED();
264 return false;
265 }
266 pipe_ = channel_handle.socket.fd;
267 return true;
[email protected]456b0ea2012-03-30 19:57:22268}
269
[email protected]2f60c9b2014-06-06 20:13:51270bool ChannelNacl::ProcessOutgoingMessages() {
[email protected]4e8f0a762012-05-31 19:37:54271 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
272 // no connection?
273 if (output_queue_.empty())
274 return true;
275
276 if (pipe_ == -1)
277 return false;
278
279 // Write out all the messages. The trusted implementation is guaranteed to not
280 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
281 while (!output_queue_.empty()) {
282 linked_ptr<Message> msg = output_queue_.front();
283 output_queue_.pop_front();
284
morrita4b5c28e22015-01-14 21:17:06285 int fds[MessageAttachmentSet::kMaxDescriptorsPerMessage];
286 const size_t num_fds = msg->attachment_set()->size();
287 DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
288 msg->attachment_set()->PeekDescriptors(fds);
[email protected]ff79fa22012-07-10 17:26:03289
[email protected]18ff3c32013-06-05 23:37:11290 NaClAbiNaClImcMsgIoVec iov = {
291 const_cast<void*>(msg->data()), msg->size()
292 };
293 NaClAbiNaClImcMsgHdr msgh = { &iov, 1, fds, num_fds };
[email protected]4e8f0a762012-05-31 19:37:54294 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0);
295
[email protected]ff79fa22012-07-10 17:26:03296 DCHECK(bytes_written); // The trusted side shouldn't return 0.
[email protected]4e8f0a762012-05-31 19:37:54297 if (bytes_written < 0) {
298 // The trusted side should only ever give us an error of EPIPE. We
299 // should never be interrupted, nor should we get EAGAIN.
300 DCHECK(errno == EPIPE);
301 Close();
302 PLOG(ERROR) << "pipe_ error on "
303 << pipe_
304 << " Currently writing message of size: "
305 << msg->size();
306 return false;
[email protected]ff79fa22012-07-10 17:26:03307 } else {
morrita4b5c28e22015-01-14 21:17:06308 msg->attachment_set()->CommitAll();
[email protected]4e8f0a762012-05-31 19:37:54309 }
310
311 // Message sent OK!
312 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
313 << " on fd " << pipe_;
314 }
315 return true;
[email protected]456b0ea2012-03-30 19:57:22316}
317
[email protected]2f60c9b2014-06-06 20:13:51318void ChannelNacl::CallOnChannelConnected() {
319 listener()->OnChannelConnected(GetPeerPID());
[email protected]7e3d7522014-03-20 21:00:50320}
321
[email protected]2f60c9b2014-06-06 20:13:51322ChannelNacl::ReadState ChannelNacl::ReadData(
[email protected]4e8f0a762012-05-31 19:37:54323 char* buffer,
324 int buffer_len,
325 int* bytes_read) {
326 *bytes_read = 0;
327 if (pipe_ == -1)
328 return READ_FAILED;
329 if (read_queue_.empty())
330 return READ_PENDING;
331 while (!read_queue_.empty() && *bytes_read < buffer_len) {
332 linked_ptr<std::vector<char> > vec(read_queue_.front());
[email protected]74ca23f2012-09-24 04:49:10333 size_t bytes_to_read = buffer_len - *bytes_read;
[email protected]4e8f0a762012-05-31 19:37:54334 if (vec->size() <= bytes_to_read) {
335 // We can read and discard the entire vector.
336 std::copy(vec->begin(), vec->end(), buffer + *bytes_read);
337 *bytes_read += vec->size();
338 read_queue_.pop_front();
339 } else {
340 // Read all the bytes we can and discard them from the front of the
341 // vector. (This can be slowish, since erase has to move the back of the
342 // vector to the front, but it's hopefully a temporary hack and it keeps
343 // the code simple).
344 std::copy(vec->begin(), vec->begin() + bytes_to_read,
345 buffer + *bytes_read);
346 vec->erase(vec->begin(), vec->begin() + bytes_to_read);
347 *bytes_read += bytes_to_read;
348 }
349 }
350 return READ_SUCCEEDED;
[email protected]fe5d4062012-04-23 21:18:19351}
352
[email protected]2f60c9b2014-06-06 20:13:51353bool ChannelNacl::WillDispatchInputMessage(Message* msg) {
[email protected]ff79fa22012-07-10 17:26:03354 uint16 header_fds = msg->header()->num_fds;
355 CHECK(header_fds == input_fds_.size());
356 if (header_fds == 0)
357 return true; // Nothing to do.
358
359 // The shenaniganery below with &foo.front() requires input_fds_ to have
360 // contiguous underlying storage (such as a simple array or a std::vector).
361 // This is why the header warns not to make input_fds_ a deque<>.
morrita4b5c28e22015-01-14 21:17:06362 msg->attachment_set()->AddDescriptorsToOwn(&input_fds_.front(), header_fds);
[email protected]ff79fa22012-07-10 17:26:03363 input_fds_.clear();
[email protected]4e8f0a762012-05-31 19:37:54364 return true;
[email protected]fe5d4062012-04-23 21:18:19365}
366
[email protected]2f60c9b2014-06-06 20:13:51367bool ChannelNacl::DidEmptyInputBuffers() {
[email protected]ff79fa22012-07-10 17:26:03368 // When the input data buffer is empty, the fds should be too.
369 return input_fds_.empty();
[email protected]fe5d4062012-04-23 21:18:19370}
371
[email protected]2f60c9b2014-06-06 20:13:51372void ChannelNacl::HandleInternalMessage(const Message& msg) {
[email protected]4e8f0a762012-05-31 19:37:54373 // The trusted side IPC::Channel should handle the "hello" handshake; we
374 // should not receive the "Hello" message.
375 NOTREACHED();
[email protected]456b0ea2012-03-30 19:57:22376}
377
[email protected]2f60c9b2014-06-06 20:13:51378// Channel's methods
[email protected]456b0ea2012-03-30 19:57:22379
[email protected]2f60c9b2014-06-06 20:13:51380// static
erikchen27aa7d82015-06-16 21:21:04381scoped_ptr<Channel> Channel::Create(const IPC::ChannelHandle& channel_handle,
382 Mode mode,
383 Listener* listener,
384 AttachmentBroker* broker) {
[email protected]2f60c9b2014-06-06 20:13:51385 return scoped_ptr<Channel>(
erikchen27aa7d82015-06-16 21:21:04386 new ChannelNacl(channel_handle, mode, listener, broker));
[email protected]456b0ea2012-03-30 19:57:22387}
388
[email protected]456b0ea2012-03-30 19:57:22389} // namespace IPC