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.
5 #include "chrome/nacl/nacl_ipc_adapter.h"
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/shared_memory.h"
15 #include "build/build_config.h"
16 #include "ipc/ipc_channel.h"
17 #include "ipc/ipc_platform_file.h"
18 #include "native_client/src/trusted/desc/nacl_desc_base.h"
19 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
20 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
21 #include "native_client/src/trusted/desc/nacl_desc_io.h"
22 #include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
23 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
24 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
25 #include "ppapi/c/ppb_file_io.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27 #include "ppapi/proxy/serialized_handle.h"
31 enum BufferSizeStatus
{
32 // The buffer contains a full message with no extra bytes.
35 // The message doesn't fit and the buffer contains only some of it.
38 // The buffer contains a full message + extra data.
39 MESSAGE_HAS_EXTRA_DATA
42 BufferSizeStatus
GetBufferStatus(const char* data
, size_t len
) {
43 if (len
< sizeof(NaClIPCAdapter::NaClMessageHeader
))
44 return MESSAGE_IS_TRUNCATED
;
46 const NaClIPCAdapter::NaClMessageHeader
* header
=
47 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader
*>(data
);
49 sizeof(NaClIPCAdapter::NaClMessageHeader
) + header
->payload_size
;
51 if (len
== message_size
)
52 return MESSAGE_IS_COMPLETE
;
53 if (len
> message_size
)
54 return MESSAGE_HAS_EXTRA_DATA
;
55 return MESSAGE_IS_TRUNCATED
;
58 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
59 // forward calls to it.
61 explicit DescThunker(NaClIPCAdapter
* adapter_param
)
62 : adapter(adapter_param
) {
64 scoped_refptr
<NaClIPCAdapter
> adapter
;
67 NaClIPCAdapter
* ToAdapter(void* handle
) {
68 return static_cast<DescThunker
*>(handle
)->adapter
.get();
71 // NaClDescCustom implementation.
72 void NaClDescCustomDestroy(void* handle
) {
73 delete static_cast<DescThunker
*>(handle
);
76 ssize_t
NaClDescCustomSendMsg(void* handle
, const NaClImcTypedMsgHdr
* msg
,
78 return static_cast<ssize_t
>(ToAdapter(handle
)->Send(msg
));
81 ssize_t
NaClDescCustomRecvMsg(void* handle
, NaClImcTypedMsgHdr
* msg
,
83 return static_cast<ssize_t
>(ToAdapter(handle
)->BlockingReceive(msg
));
86 NaClDesc
* MakeNaClDescCustom(NaClIPCAdapter
* adapter
) {
87 NaClDescCustomFuncs funcs
= NACL_DESC_CUSTOM_FUNCS_INITIALIZER
;
88 funcs
.Destroy
= NaClDescCustomDestroy
;
89 funcs
.SendMsg
= NaClDescCustomSendMsg
;
90 funcs
.RecvMsg
= NaClDescCustomRecvMsg
;
91 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc.
92 return NaClDescMakeCustomDesc(new DescThunker(adapter
), &funcs
);
95 void DeleteChannel(IPC::Channel
* channel
) {
99 // Translates Pepper's read/write open flags into NaCl's ones. The other open
100 // flags are discarded. If neither of the read/write flags is specified, just
101 // returns NACL_ABI_O_RDONLY as a safe fallback.
102 int TranslatePepperFileReadWriteOpenFlags(int32_t pp_open_flags
) {
104 if ((pp_open_flags
& (PP_FILEOPENFLAG_READ
| PP_FILEOPENFLAG_WRITE
)) ==
105 (PP_FILEOPENFLAG_READ
| PP_FILEOPENFLAG_WRITE
)) {
106 nacl_open_flag
= NACL_ABI_O_RDWR
;
107 } else if (pp_open_flags
& PP_FILEOPENFLAG_READ
) {
108 nacl_open_flag
= NACL_ABI_O_RDONLY
;
109 } else if (pp_open_flags
& PP_FILEOPENFLAG_WRITE
) {
110 nacl_open_flag
= NACL_ABI_O_WRONLY
;
112 DLOG(WARNING
) << "PP_FILEOPENFLAG_READ and/or PP_FILEOPENFLAG_WRITE "
113 << "should be specified.";
114 // NACL_ABI_O_RDONLY == 0, so make this ambiguous case readonly as a safe
116 nacl_open_flag
= NACL_ABI_O_RDONLY
;
118 return nacl_open_flag
;
121 class NaClDescWrapper
{
123 explicit NaClDescWrapper(NaClDesc
* desc
): desc_(desc
) {}
125 NaClDescUnref(desc_
);
128 NaClDesc
* desc() { return desc_
; }
132 DISALLOW_COPY_AND_ASSIGN(NaClDescWrapper
);
137 class NaClIPCAdapter::RewrittenMessage
138 : public base::RefCounted
<RewrittenMessage
> {
142 bool is_consumed() const { return data_read_cursor_
== data_len_
; }
144 void SetData(const NaClIPCAdapter::NaClMessageHeader
& header
,
145 const void* payload
, size_t payload_length
);
147 int Read(NaClImcTypedMsgHdr
* msg
);
149 void AddDescriptor(NaClDescWrapper
* desc
) { descs_
.push_back(desc
); }
151 size_t desc_count() const { return descs_
.size(); }
154 friend class base::RefCounted
<RewrittenMessage
>;
155 ~RewrittenMessage() {}
157 scoped_ptr
<char[]> data_
;
160 // Offset into data where the next read will happen. This will be equal to
161 // data_len_ when all data has been consumed.
162 size_t data_read_cursor_
;
164 // Wrapped descriptors for transfer to untrusted code.
165 ScopedVector
<NaClDescWrapper
> descs_
;
168 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
170 data_read_cursor_(0) {
173 void NaClIPCAdapter::RewrittenMessage::SetData(
174 const NaClIPCAdapter::NaClMessageHeader
& header
,
176 size_t payload_length
) {
177 DCHECK(!data_
.get() && data_len_
== 0);
178 size_t header_len
= sizeof(NaClIPCAdapter::NaClMessageHeader
);
179 data_len_
= header_len
+ payload_length
;
180 data_
.reset(new char[data_len_
]);
182 memcpy(data_
.get(), &header
, sizeof(NaClIPCAdapter::NaClMessageHeader
));
183 memcpy(&data_
[header_len
], payload
, payload_length
);
186 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr
* msg
) {
187 CHECK(data_len_
>= data_read_cursor_
);
188 char* dest_buffer
= static_cast<char*>(msg
->iov
[0].base
);
189 size_t dest_buffer_size
= msg
->iov
[0].length
;
190 size_t bytes_to_write
= std::min(dest_buffer_size
,
191 data_len_
- data_read_cursor_
);
192 if (bytes_to_write
== 0)
195 memcpy(dest_buffer
, &data_
[data_read_cursor_
], bytes_to_write
);
196 data_read_cursor_
+= bytes_to_write
;
198 // Once all data has been consumed, transfer any file descriptors.
200 nacl_abi_size_t desc_count
= static_cast<nacl_abi_size_t
>(descs_
.size());
201 CHECK(desc_count
<= msg
->ndesc_length
);
202 msg
->ndesc_length
= desc_count
;
203 for (nacl_abi_size_t i
= 0; i
< desc_count
; i
++) {
204 // Copy the NaClDesc to the buffer and add a ref so it won't be freed
205 // when we clear our ScopedVector.
206 msg
->ndescv
[i
] = descs_
[i
]->desc();
207 NaClDescRef(descs_
[i
]->desc());
211 msg
->ndesc_length
= 0;
213 return static_cast<int>(bytes_to_write
);
216 NaClIPCAdapter::LockedData::LockedData()
217 : channel_closed_(false) {
220 NaClIPCAdapter::LockedData::~LockedData() {
223 NaClIPCAdapter::IOThreadData::IOThreadData() {
226 NaClIPCAdapter::IOThreadData::~IOThreadData() {
229 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle
& handle
,
230 base::TaskRunner
* runner
)
233 task_runner_(runner
),
235 io_thread_data_
.channel_
.reset(
236 new IPC::Channel(handle
, IPC::Channel::MODE_SERVER
, this));
237 // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did,
238 // and that task ran before this constructor completes, the reference count
239 // would go to 1 and then to 0 because of the Task, before we've been returned
240 // to the owning scoped_refptr, which is supposed to give us our first
244 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr
<IPC::Channel
> channel
,
245 base::TaskRunner
* runner
)
248 task_runner_(runner
),
250 io_thread_data_
.channel_
= channel
.Pass();
253 void NaClIPCAdapter::ConnectChannel() {
254 task_runner_
->PostTask(FROM_HERE
,
255 base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread
, this));
258 // Note that this message is controlled by the untrusted code. So we should be
259 // skeptical of anything it contains and quick to give up if anything is fishy.
260 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr
* msg
) {
261 if (msg
->iov_length
!= 1)
264 base::AutoLock
lock(lock_
);
266 const char* input_data
= static_cast<char*>(msg
->iov
[0].base
);
267 size_t input_data_len
= msg
->iov
[0].length
;
268 if (input_data_len
> IPC::Channel::kMaximumMessageSize
) {
273 // current_message[_len] refers to the total input data received so far.
274 const char* current_message
;
275 size_t current_message_len
;
276 bool did_append_input_data
;
277 if (locked_data_
.to_be_sent_
.empty()) {
278 // No accumulated data, we can avoid a copy by referring to the input
279 // buffer (the entire message fitting in one call is the common case).
280 current_message
= input_data
;
281 current_message_len
= input_data_len
;
282 did_append_input_data
= false;
284 // We've already accumulated some data, accumulate this new data and
285 // point to the beginning of the buffer.
287 // Make sure our accumulated message size doesn't overflow our max. Since
288 // we know that data_len < max size (checked above) and our current
289 // accumulated value is also < max size, we just need to make sure that
290 // 2x max size can never overflow.
291 COMPILE_ASSERT(IPC::Channel::kMaximumMessageSize
< (UINT_MAX
/ 2),
292 MaximumMessageSizeWillOverflow
);
293 size_t new_size
= locked_data_
.to_be_sent_
.size() + input_data_len
;
294 if (new_size
> IPC::Channel::kMaximumMessageSize
) {
299 locked_data_
.to_be_sent_
.append(input_data
, input_data_len
);
300 current_message
= &locked_data_
.to_be_sent_
[0];
301 current_message_len
= locked_data_
.to_be_sent_
.size();
302 did_append_input_data
= true;
305 // Check the total data we've accumulated so far to see if it contains a full
307 switch (GetBufferStatus(current_message
, current_message_len
)) {
308 case MESSAGE_IS_COMPLETE
: {
309 // Got a complete message, can send it out. This will be the common case.
310 bool success
= SendCompleteMessage(current_message
, current_message_len
);
312 return success
? static_cast<int>(input_data_len
) : -1;
314 case MESSAGE_IS_TRUNCATED
:
315 // For truncated messages, just accumulate the new data (if we didn't
316 // already do so above) and go back to waiting for more.
317 if (!did_append_input_data
)
318 locked_data_
.to_be_sent_
.append(input_data
, input_data_len
);
319 return static_cast<int>(input_data_len
);
320 case MESSAGE_HAS_EXTRA_DATA
:
322 // When the plugin gives us too much data, it's an error.
328 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr
* msg
) {
329 if (msg
->iov_length
!= 1)
334 base::AutoLock
lock(lock_
);
335 while (locked_data_
.to_be_received_
.empty() &&
336 !locked_data_
.channel_closed_
)
338 if (locked_data_
.channel_closed_
) {
341 retval
= LockedReceive(msg
);
349 void NaClIPCAdapter::CloseChannel() {
351 base::AutoLock
lock(lock_
);
352 locked_data_
.channel_closed_
= true;
356 task_runner_
->PostTask(FROM_HERE
,
357 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread
, this));
360 NaClDesc
* NaClIPCAdapter::MakeNaClDesc() {
361 return MakeNaClDescCustom(this);
364 #if defined(OS_POSIX)
365 int NaClIPCAdapter::TakeClientFileDescriptor() {
366 return io_thread_data_
.channel_
->TakeClientFileDescriptor();
370 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message
& msg
) {
372 base::AutoLock
lock(lock_
);
374 scoped_refptr
<RewrittenMessage
> rewritten_msg(new RewrittenMessage
);
376 typedef std::vector
<ppapi::proxy::SerializedHandle
> Handles
;
378 scoped_ptr
<IPC::Message
> new_msg_ptr
;
379 bool success
= locked_data_
.handle_converter_
.ConvertNativeHandlesToPosix(
380 msg
, &handles
, &new_msg_ptr
);
384 // Now add any descriptors we found to rewritten_msg. |handles| is usually
385 // empty, unless we read a message containing a FD or handle.
386 for (Handles::const_iterator iter
= handles
.begin();
387 iter
!= handles
.end();
389 scoped_ptr
<NaClDescWrapper
> nacl_desc
;
390 switch (iter
->type()) {
391 case ppapi::proxy::SerializedHandle::SHARED_MEMORY
: {
392 const base::SharedMemoryHandle
& shm_handle
= iter
->shmem();
393 uint32_t size
= iter
->size();
394 nacl_desc
.reset(new NaClDescWrapper(NaClDescImcShmMake(
400 static_cast<size_t>(size
))));
403 case ppapi::proxy::SerializedHandle::SOCKET
: {
404 nacl_desc
.reset(new NaClDescWrapper(NaClDescSyncSocketMake(
408 iter
->descriptor().fd
413 case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE
: {
414 // Check that this came from a PpapiMsg_CreateNaClChannel message.
415 // This code here is only appropriate for that message.
416 DCHECK(msg
.type() == PpapiMsg_CreateNaClChannel::ID
);
417 IPC::ChannelHandle channel_handle
=
418 IPC::Channel::GenerateVerifiedChannelID("nacl");
419 scoped_refptr
<NaClIPCAdapter
> ipc_adapter(
420 new NaClIPCAdapter(channel_handle
, task_runner_
.get()));
421 ipc_adapter
->ConnectChannel();
422 #if defined(OS_POSIX)
423 channel_handle
.socket
= base::FileDescriptor(
424 ipc_adapter
->TakeClientFileDescriptor(), true);
426 nacl_desc
.reset(new NaClDescWrapper(ipc_adapter
->MakeNaClDesc()));
427 // Send back a message that the channel was created.
428 scoped_ptr
<IPC::Message
> response(
429 new PpapiHostMsg_ChannelCreated(channel_handle
));
430 task_runner_
->PostTask(FROM_HERE
,
431 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread
, this,
432 base::Passed(&response
)));
435 case ppapi::proxy::SerializedHandle::FILE:
436 nacl_desc
.reset(new NaClDescWrapper(NaClDescIoDescFromHandleAllocCtor(
440 iter
->descriptor().fd
,
442 TranslatePepperFileReadWriteOpenFlags(iter
->open_flag()))));
444 case ppapi::proxy::SerializedHandle::INVALID
: {
445 // Nothing to do. TODO(dmichael): Should we log this? Or is it
446 // sometimes okay to pass an INVALID handle?
449 // No default, so the compiler will warn us if new types get added.
452 rewritten_msg
->AddDescriptor(nacl_desc
.release());
454 if (new_msg_ptr
&& !handles
.empty())
455 SaveMessage(*new_msg_ptr
, rewritten_msg
.get());
457 SaveMessage(msg
, rewritten_msg
.get());
463 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid
) {
466 void NaClIPCAdapter::OnChannelError() {
470 NaClIPCAdapter::~NaClIPCAdapter() {
471 // Make sure the channel is deleted on the IO thread.
472 task_runner_
->PostTask(FROM_HERE
,
473 base::Bind(&DeleteChannel
, io_thread_data_
.channel_
.release()));
476 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr
* msg
) {
477 lock_
.AssertAcquired();
479 if (locked_data_
.to_be_received_
.empty())
481 scoped_refptr
<RewrittenMessage
> current
=
482 locked_data_
.to_be_received_
.front();
484 int retval
= current
->Read(msg
);
486 // When a message is entirely consumed, remove if from the waiting queue.
487 if (current
->is_consumed())
488 locked_data_
.to_be_received_
.pop();
493 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer
,
495 lock_
.AssertAcquired();
496 // The message will have already been validated, so we know it's large enough
498 const NaClMessageHeader
* header
=
499 reinterpret_cast<const NaClMessageHeader
*>(buffer
);
501 // Length of the message not including the body. The data passed to us by the
502 // plugin should match that in the message header. This should have already
503 // been validated by GetBufferStatus.
504 int body_len
= static_cast<int>(buffer_len
- sizeof(NaClMessageHeader
));
505 DCHECK(body_len
== static_cast<int>(header
->payload_size
));
507 // We actually discard the flags and only copy the ones we care about. This
508 // is just because message doesn't have a constructor that takes raw flags.
509 scoped_ptr
<IPC::Message
> msg(
510 new IPC::Message(header
->routing
, header
->type
,
511 IPC::Message::PRIORITY_NORMAL
));
512 if (header
->flags
& IPC::Message::SYNC_BIT
)
514 if (header
->flags
& IPC::Message::REPLY_BIT
)
516 if (header
->flags
& IPC::Message::REPLY_ERROR_BIT
)
517 msg
->set_reply_error();
518 if (header
->flags
& IPC::Message::UNBLOCK_BIT
)
519 msg
->set_unblock(true);
521 msg
->WriteBytes(&buffer
[sizeof(NaClMessageHeader
)], body_len
);
523 // Technically we didn't have to do any of the previous work in the lock. But
524 // sometimes our buffer will point to the to_be_sent_ string which is
525 // protected by the lock, and it's messier to factor Send() such that it can
526 // unlock for us. Holding the lock for the message construction, which is
527 // just some memcpys, shouldn't be a big deal.
528 lock_
.AssertAcquired();
529 if (locked_data_
.channel_closed_
)
530 return false; // TODO(brettw) clean up handles here when we add support!
532 if (msg
->is_sync()) {
533 locked_data_
.handle_converter_
.RegisterSyncMessageForReply(*msg
);
535 // Actual send must be done on the I/O thread.
536 task_runner_
->PostTask(FROM_HERE
,
537 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread
, this,
538 base::Passed(&msg
)));
542 void NaClIPCAdapter::ClearToBeSent() {
543 lock_
.AssertAcquired();
545 // Don't let the string keep its buffer behind our back.
547 locked_data_
.to_be_sent_
.swap(empty
);
550 void NaClIPCAdapter::ConnectChannelOnIOThread() {
551 if (!io_thread_data_
.channel_
->Connect())
555 void NaClIPCAdapter::CloseChannelOnIOThread() {
556 io_thread_data_
.channel_
->Close();
559 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr
<IPC::Message
> message
) {
560 io_thread_data_
.channel_
->Send(message
.release());
563 void NaClIPCAdapter::SaveMessage(const IPC::Message
& msg
,
564 RewrittenMessage
* rewritten_msg
) {
565 lock_
.AssertAcquired();
566 // There is some padding in this structure (the "padding" member is 16
567 // bits but this then gets padded to 32 bits). We want to be sure not to
568 // leak data to the untrusted plugin, so zero everything out first.
569 NaClMessageHeader header
;
570 memset(&header
, 0, sizeof(NaClMessageHeader
));
572 header
.payload_size
= static_cast<uint32
>(msg
.payload_size());
573 header
.routing
= msg
.routing_id();
574 header
.type
= msg
.type();
575 header
.flags
= msg
.flags();
576 header
.num_fds
= static_cast<int>(rewritten_msg
->desc_count());
578 rewritten_msg
->SetData(header
, msg
.payload(), msg
.payload_size());
579 locked_data_
.to_be_received_
.push(rewritten_msg
);
582 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags
) {
583 return TranslatePepperFileReadWriteOpenFlags(pp_open_flags
);