1 // 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
7 #include <errno.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <sys/types.h>
11
12 #include <algorithm>
13
14 #include "base/bind.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/message_loop/message_pump_for_io.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/synchronization/lock.h"
21 #include "base/task_runner_util.h"
22 #include "base/threading/simple_thread.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "ipc/ipc_listener.h"
25 #include "ipc/ipc_logging.h"
26 #include "ipc/ipc_message_attachment_set.h"
27 #include "ipc/ipc_platform_file_attachment_posix.h"
28 #include "native_client/src/public/imc_syscalls.h"
29 #include "native_client/src/public/imc_types.h"
30
31 namespace IPC {
32
33 struct MessageContents {
34 std::vector<char> data;
35 std::vector<int> fds;
36 };
37
38 namespace {
39
ReadDataOnReaderThread(int pipe,MessageContents * contents)40 bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
41 DCHECK(pipe >= 0);
42 if (pipe < 0)
43 return false;
44
45 contents->data.resize(Channel::kReadBufferSize);
46 contents->fds.resize(NACL_ABI_IMC_DESC_MAX);
47
48 NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() };
49 NaClAbiNaClImcMsgHdr msg = {
50 &iov, 1, &contents->fds[0], contents->fds.size()
51 };
52
53 int bytes_read = imc_recvmsg(pipe, &msg, 0);
54
55 if (bytes_read <= 0) {
56 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
57 // due to error or for regular shutdown).
58 contents->data.clear();
59 contents->fds.clear();
60 return false;
61 }
62 DCHECK(bytes_read);
63 // Resize the buffers down to the number of bytes and fds we actually read.
64 contents->data.resize(bytes_read);
65 contents->fds.resize(msg.desc_length);
66 return true;
67 }
68
69 } // namespace
70
71 // static
72 constexpr size_t Channel::kMaximumMessageSize;
73
74 class ChannelNacl::ReaderThreadRunner
75 : public base::DelegateSimpleThread::Delegate {
76 public:
77 // |pipe|: A file descriptor from which we will read using imc_recvmsg.
78 // |data_read_callback|: A callback we invoke (on the main thread) when we
79 // have read data.
80 // |failure_callback|: A callback we invoke when we have a failure reading
81 // from |pipe|.
82 // |main_message_loop|: A proxy for the main thread, where we will invoke the
83 // above callbacks.
84 ReaderThreadRunner(
85 int pipe,
86 base::Callback<void(std::unique_ptr<MessageContents>)> data_read_callback,
87 base::Callback<void()> failure_callback,
88 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
89
90 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
91 // until either we are told to quit or a read fails.
92 void Run() override;
93
94 private:
95 int pipe_;
96 base::Callback<void(std::unique_ptr<MessageContents>)> data_read_callback_;
97 base::Callback<void ()> failure_callback_;
98 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
99
100 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
101 };
102
ReaderThreadRunner(int pipe,base::Callback<void (std::unique_ptr<MessageContents>)> data_read_callback,base::Callback<void ()> failure_callback,scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)103 ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
104 int pipe,
105 base::Callback<void(std::unique_ptr<MessageContents>)> data_read_callback,
106 base::Callback<void()> failure_callback,
107 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
108 : pipe_(pipe),
109 data_read_callback_(data_read_callback),
110 failure_callback_(failure_callback),
111 main_task_runner_(main_task_runner) {}
112
Run()113 void ChannelNacl::ReaderThreadRunner::Run() {
114 while (true) {
115 std::unique_ptr<MessageContents> msg_contents(new MessageContents);
116 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
117 if (success) {
118 main_task_runner_->PostTask(
119 FROM_HERE,
120 base::Bind(data_read_callback_, base::Passed(&msg_contents)));
121 } else {
122 main_task_runner_->PostTask(FROM_HERE, failure_callback_);
123 // Because the read failed, we know we're going to quit. Don't bother
124 // trying to read again.
125 return;
126 }
127 }
128 }
129
ChannelNacl(const IPC::ChannelHandle & channel_handle,Mode mode,Listener * listener)130 ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
131 Mode mode,
132 Listener* listener)
133 : ChannelReader(listener),
134 mode_(mode),
135 waiting_connect_(true),
136 pipe_(-1),
137 weak_ptr_factory_(this) {
138 if (!CreatePipe(channel_handle)) {
139 // The pipe may have been closed already.
140 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
141 LOG(WARNING) << "Unable to create pipe in " << modestr << " mode";
142 }
143 }
144
~ChannelNacl()145 ChannelNacl::~ChannelNacl() {
146 CleanUp();
147 Close();
148 }
149
Connect()150 bool ChannelNacl::Connect() {
151 WillConnect();
152
153 if (pipe_ == -1) {
154 DLOG(WARNING) << "Channel creation failed";
155 return false;
156 }
157
158 // Note that Connect is called on the "Channel" thread (i.e., the same thread
159 // where Channel::Send will be called, and the same thread that should receive
160 // messages). The constructor might be invoked on another thread (see
161 // ChannelProxy for an example of that). Therefore, we must wait until Connect
162 // is called to decide which SingleThreadTaskRunner to pass to
163 // ReaderThreadRunner.
164 reader_thread_runner_.reset(new ReaderThreadRunner(
165 pipe_,
166 base::Bind(&ChannelNacl::DidRecvMsg, weak_ptr_factory_.GetWeakPtr()),
167 base::Bind(&ChannelNacl::ReadDidFail, weak_ptr_factory_.GetWeakPtr()),
168 base::ThreadTaskRunnerHandle::Get()));
169 reader_thread_.reset(
170 new base::DelegateSimpleThread(reader_thread_runner_.get(),
171 "ipc_channel_nacl reader thread"));
172 reader_thread_->Start();
173 waiting_connect_ = false;
174 // If there were any messages queued before connection, send them.
175 ProcessOutgoingMessages();
176 base::ThreadTaskRunnerHandle::Get()->PostTask(
177 FROM_HERE, base::Bind(&ChannelNacl::CallOnChannelConnected,
178 weak_ptr_factory_.GetWeakPtr()));
179
180 return true;
181 }
182
Close()183 void ChannelNacl::Close() {
184 // For now, we assume that at shutdown, the reader thread will be woken with
185 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
186 // might simply be killed with no chance to clean up anyway :-).
187 // If untrusted code tries to close the channel prior to shutdown, it's likely
188 // to hang.
189 // TODO(dmichael): Can we do anything smarter here to make sure the reader
190 // thread wakes up and quits?
191 reader_thread_->Join();
192 close(pipe_);
193 pipe_ = -1;
194 reader_thread_runner_.reset();
195 reader_thread_.reset();
196 read_queue_.clear();
197 output_queue_.clear();
198 }
199
Send(Message * message)200 bool ChannelNacl::Send(Message* message) {
201 DCHECK(!message->HasAttachments());
202 DVLOG(2) << "sending message @" << message << " on channel @" << this
203 << " with type " << message->type();
204 std::unique_ptr<Message> message_ptr(message);
205
206 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
207 Logging::GetInstance()->OnSendMessage(message_ptr.get());
208 #endif // BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
209
210 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
211 "ChannelNacl::Send",
212 message->header()->flags,
213 TRACE_EVENT_FLAG_FLOW_OUT);
214 output_queue_.push_back(std::move(message_ptr));
215 if (!waiting_connect_)
216 return ProcessOutgoingMessages();
217
218 return true;
219 }
220
DidRecvMsg(std::unique_ptr<MessageContents> contents)221 void ChannelNacl::DidRecvMsg(std::unique_ptr<MessageContents> contents) {
222 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
223 // the reader thread after Close is called. If so, we ignore it.
224 if (pipe_ == -1)
225 return;
226
227 auto data = std::make_unique<std::vector<char>>();
228 data->swap(contents->data);
229 read_queue_.push_back(std::move(data));
230
231 input_attachments_.reserve(contents->fds.size());
232 for (int fd : contents->fds) {
233 input_attachments_.push_back(
234 new internal::PlatformFileAttachment(base::ScopedFD(fd)));
235 }
236 contents->fds.clear();
237
238 // In POSIX, we would be told when there are bytes to read by implementing
239 // OnFileCanReadWithoutBlocking in MessagePumpForIO::FdWatcher. In NaCl, we
240 // instead know at this point because the reader thread posted some data to
241 // us.
242 ProcessIncomingMessages();
243 }
244
ReadDidFail()245 void ChannelNacl::ReadDidFail() {
246 Close();
247 }
248
CreatePipe(const IPC::ChannelHandle & channel_handle)249 bool ChannelNacl::CreatePipe(
250 const IPC::ChannelHandle& channel_handle) {
251 DCHECK(pipe_ == -1);
252
253 // There's one possible case in NaCl:
254 // 1) It's a channel wrapping a pipe that is given to us.
255 // We don't support these:
256 // 2) It's for a named channel.
257 // 3) It's for a client that we implement ourself.
258 // 4) It's the initial IPC channel.
259
260 if (channel_handle.socket.fd == -1) {
261 NOTIMPLEMENTED();
262 return false;
263 }
264 pipe_ = channel_handle.socket.fd;
265 return true;
266 }
267
ProcessOutgoingMessages()268 bool ChannelNacl::ProcessOutgoingMessages() {
269 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
270 // no connection?
271 if (output_queue_.empty())
272 return true;
273
274 if (pipe_ == -1)
275 return false;
276
277 // Write out all the messages. The trusted implementation is guaranteed to not
278 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
279 while (!output_queue_.empty()) {
280 std::unique_ptr<Message> msg = std::move(output_queue_.front());
281 output_queue_.pop_front();
282
283 const size_t num_fds = msg->attachment_set()->size();
284 DCHECK(num_fds <= MessageAttachmentSet::kMaxDescriptorsPerMessage);
285 std::vector<int> fds;
286 fds.reserve(num_fds);
287 for (size_t i = 0; i < num_fds; i++) {
288 scoped_refptr<MessageAttachment> attachment =
289 msg->attachment_set()->GetAttachmentAt(i);
290 DCHECK_EQ(MessageAttachment::Type::PLATFORM_FILE, attachment->GetType());
291 fds.push_back(static_cast<internal::PlatformFileAttachment&>(*attachment)
292 .TakePlatformFile());
293 }
294
295 NaClAbiNaClImcMsgIoVec iov = {
296 const_cast<void*>(msg->data()), msg->size()
297 };
298 NaClAbiNaClImcMsgHdr msgh = {&iov, 1, fds.data(), num_fds};
299 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0);
300
301 DCHECK(bytes_written); // The trusted side shouldn't return 0.
302 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;
312 } else {
313 msg->attachment_set()->CommitAllDescriptors();
314 }
315
316 // Message sent OK!
317 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
318 << " on fd " << pipe_;
319 }
320 return true;
321 }
322
CallOnChannelConnected()323 void ChannelNacl::CallOnChannelConnected() {
324 listener()->OnChannelConnected(-1);
325 }
326
ReadData(char * buffer,int buffer_len,int * bytes_read)327 ChannelNacl::ReadState ChannelNacl::ReadData(
328 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 std::vector<char>* vec = read_queue_.front().get();
338 size_t bytes_to_read = buffer_len - *bytes_read;
339 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;
356 }
357
ShouldDispatchInputMessage(Message * msg)358 bool ChannelNacl::ShouldDispatchInputMessage(Message* msg) {
359 return true;
360 }
361
GetAttachments(Message * msg)362 bool ChannelNacl::GetAttachments(Message* msg) {
363 uint16_t header_fds = msg->header()->num_fds;
364 CHECK(header_fds == input_attachments_.size());
365 if (header_fds == 0)
366 return true; // Nothing to do.
367
368 for (auto& attachment : input_attachments_) {
369 msg->attachment_set()->AddAttachment(std::move(attachment));
370 }
371 input_attachments_.clear();
372 return true;
373 }
374
DidEmptyInputBuffers()375 bool ChannelNacl::DidEmptyInputBuffers() {
376 // When the input data buffer is empty, the attachments should be too.
377 return input_attachments_.empty();
378 }
379
HandleInternalMessage(const Message & msg)380 void ChannelNacl::HandleInternalMessage(const Message& msg) {
381 // The trusted side IPC::Channel should handle the "hello" handshake; we
382 // should not receive the "Hello" message.
383 NOTREACHED();
384 }
385
386 // Channel's methods
387
388 // static
Create(const IPC::ChannelHandle & channel_handle,Mode mode,Listener * listener)389 std::unique_ptr<Channel> Channel::Create(
390 const IPC::ChannelHandle& channel_handle,
391 Mode mode,
392 Listener* listener) {
393 return std::make_unique<ChannelNacl>(channel_handle, mode, listener);
394 }
395
396 } // namespace IPC
397