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_message_macros.h"
17 #include "ipc/ipc_platform_file.h"
18 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
19 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
20 #include "ppapi/proxy/ppapi_messages.h"
24 enum BufferSizeStatus
{
25 // The buffer contains a full message with no extra bytes.
28 // The message doesn't fit and the buffer contains only some of it.
31 // The buffer contains a full message + extra data.
32 MESSAGE_HAS_EXTRA_DATA
35 BufferSizeStatus
GetBufferStatus(const char* data
, size_t len
) {
36 if (len
< sizeof(NaClIPCAdapter::NaClMessageHeader
))
37 return MESSAGE_IS_TRUNCATED
;
39 const NaClIPCAdapter::NaClMessageHeader
* header
=
40 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader
*>(data
);
42 sizeof(NaClIPCAdapter::NaClMessageHeader
) + header
->payload_size
;
44 if (len
== message_size
)
45 return MESSAGE_IS_COMPLETE
;
46 if (len
> message_size
)
47 return MESSAGE_HAS_EXTRA_DATA
;
48 return MESSAGE_IS_TRUNCATED
;
51 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and
52 // forward calls to it.
54 explicit DescThunker(NaClIPCAdapter
* adapter_param
)
55 : adapter(adapter_param
) {
57 scoped_refptr
<NaClIPCAdapter
> adapter
;
60 NaClIPCAdapter
* ToAdapter(void* handle
) {
61 return static_cast<DescThunker
*>(handle
)->adapter
.get();
64 // NaClDescCustom implementation.
65 void NaClDescCustomDestroy(void* handle
) {
66 delete static_cast<DescThunker
*>(handle
);
69 ssize_t
NaClDescCustomSendMsg(void* handle
, const NaClImcTypedMsgHdr
* msg
,
71 return static_cast<ssize_t
>(ToAdapter(handle
)->Send(msg
));
74 ssize_t
NaClDescCustomRecvMsg(void* handle
, NaClImcTypedMsgHdr
* msg
,
76 return static_cast<ssize_t
>(ToAdapter(handle
)->BlockingReceive(msg
));
79 NaClDesc
* MakeNaClDescCustom(NaClIPCAdapter
* adapter
) {
80 NaClDescCustomFuncs funcs
= NACL_DESC_CUSTOM_FUNCS_INITIALIZER
;
81 funcs
.Destroy
= NaClDescCustomDestroy
;
82 funcs
.SendMsg
= NaClDescCustomSendMsg
;
83 funcs
.RecvMsg
= NaClDescCustomRecvMsg
;
84 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc.
85 return NaClDescMakeCustomDesc(new DescThunker(adapter
), &funcs
);
88 void DeleteChannel(IPC::Channel
* channel
) {
92 void WriteHandle(int handle_index
,
93 const ppapi::proxy::SerializedHandle
& handle
,
94 IPC::Message
* message
) {
95 ppapi::proxy::SerializedHandle::WriteHeader(handle
.header(), message
);
97 // Now write the handle itself in POSIX style.
98 message
->WriteBool(true); // valid == true
99 message
->WriteInt(handle_index
);
102 typedef std::vector
<ppapi::proxy::SerializedHandle
> Handles
;
104 // We define one overload for catching SerializedHandles, so that we can share
105 // them correctly to the untrusted side, and another for handling all other
106 // parameters. See ConvertHandlesImpl for how these get used.
107 void ConvertHandle(const ppapi::proxy::SerializedHandle
& handle
,
108 Handles
* handles
, IPC::Message
* msg
, int* handle_index
) {
109 handles
->push_back(handle
);
111 WriteHandle((*handle_index
)++, handle
, msg
);
114 // This overload is to catch all types other than SerializedHandle. On Windows,
115 // |msg| will be a valid pointer, and we must write |param| to it
117 void ConvertHandle(const T
& param
, Handles
* /* handles */, IPC::Message
* msg
,
118 int* /* handle_index */) {
119 // It's not a handle, so just write to the output message, if necessary.
121 IPC::WriteParam(msg
, param
);
124 // These just break apart the given tuple and run ConvertHandle over each param.
125 // The idea is to extract any handles in the tuple, while writing all data to
126 // msg (if msg is valid). The msg will only be valid on Windows, where we need
127 // to re-write all of the message parameters, writing the handles in POSIX style
130 void ConvertHandlesImpl(const Tuple1
<A
>& t1
, Handles
* handles
,
132 int handle_index
= 0;
133 ConvertHandle(t1
.a
, handles
, msg
, &handle_index
);
135 template <class A
, class B
>
136 void ConvertHandlesImpl(const Tuple2
<A
, B
>& t1
, Handles
* handles
,
138 int handle_index
= 0;
139 ConvertHandle(t1
.a
, handles
, msg
, &handle_index
);
140 ConvertHandle(t1
.b
, handles
, msg
, &handle_index
);
142 template <class A
, class B
, class C
>
143 void ConvertHandlesImpl(const Tuple3
<A
, B
, C
>& t1
, Handles
* handles
,
145 int handle_index
= 0;
146 ConvertHandle(t1
.a
, handles
, msg
, &handle_index
);
147 ConvertHandle(t1
.b
, handles
, msg
, &handle_index
);
148 ConvertHandle(t1
.c
, handles
, msg
, &handle_index
);
150 template <class A
, class B
, class C
, class D
>
151 void ConvertHandlesImpl(const Tuple4
<A
, B
, C
, D
>& t1
, Handles
* handles
,
153 int handle_index
= 0;
154 ConvertHandle(t1
.a
, handles
, msg
, &handle_index
);
155 ConvertHandle(t1
.b
, handles
, msg
, &handle_index
);
156 ConvertHandle(t1
.c
, handles
, msg
, &handle_index
);
157 ConvertHandle(t1
.d
, handles
, msg
, &handle_index
);
160 template <class MessageType
>
161 class HandleConverter
{
163 explicit HandleConverter(const IPC::Message
* msg
)
164 : msg_(static_cast<const MessageType
*>(msg
)) {
166 bool ConvertMessage(Handles
* handles
, IPC::Message
* out_msg
) {
167 typename TupleTypes
<typename
MessageType::Schema::Param
>::ValueTuple params
;
168 if (!MessageType::Read(msg_
, ¶ms
))
170 ConvertHandlesImpl(params
, handles
, out_msg
);
174 bool ConvertReply(Handles
* handles
, IPC::SyncMessage
* out_msg
) {
175 typename TupleTypes
<typename
MessageType::Schema::ReplyParam
>::ValueTuple
177 if (!MessageType::ReadReplyParam(msg_
, ¶ms
))
179 // If we need to rewrite the message (i.e., on Windows), we need to make
180 // sure we write the message id first.
182 out_msg
->set_reply();
183 int id
= IPC::SyncMessage::GetMessageId(*msg_
);
184 out_msg
->WriteInt(id
);
186 ConvertHandlesImpl(params
, handles
, out_msg
);
189 // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we
190 // ever pass handles in one of those.
193 const MessageType
* msg_
;
198 class NaClIPCAdapter::RewrittenMessage
199 : public base::RefCounted
<RewrittenMessage
> {
203 bool is_consumed() const { return data_read_cursor_
== data_len_
; }
205 void SetData(const NaClIPCAdapter::NaClMessageHeader
& header
,
206 const void* payload
, size_t payload_length
);
208 int Read(NaClImcTypedMsgHdr
* msg
);
210 void AddDescriptor(nacl::DescWrapper
* desc
) { descs_
.push_back(desc
); }
212 size_t desc_count() const { return descs_
.size(); }
215 friend class base::RefCounted
<RewrittenMessage
>;
216 ~RewrittenMessage() {}
218 scoped_array
<char> data_
;
221 // Offset into data where the next read will happen. This will be equal to
222 // data_len_ when all data has been consumed.
223 size_t data_read_cursor_
;
225 // Wrapped descriptors for transfer to untrusted code.
226 ScopedVector
<nacl::DescWrapper
> descs_
;
229 NaClIPCAdapter::RewrittenMessage::RewrittenMessage()
231 data_read_cursor_(0) {
234 void NaClIPCAdapter::RewrittenMessage::SetData(
235 const NaClIPCAdapter::NaClMessageHeader
& header
,
237 size_t payload_length
) {
238 DCHECK(!data_
.get() && data_len_
== 0);
239 size_t header_len
= sizeof(NaClIPCAdapter::NaClMessageHeader
);
240 data_len_
= header_len
+ payload_length
;
241 data_
.reset(new char[data_len_
]);
243 memcpy(data_
.get(), &header
, sizeof(NaClIPCAdapter::NaClMessageHeader
));
244 memcpy(&data_
[header_len
], payload
, payload_length
);
247 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr
* msg
) {
248 CHECK(data_len_
>= data_read_cursor_
);
249 char* dest_buffer
= static_cast<char*>(msg
->iov
[0].base
);
250 size_t dest_buffer_size
= msg
->iov
[0].length
;
251 size_t bytes_to_write
= std::min(dest_buffer_size
,
252 data_len_
- data_read_cursor_
);
253 if (bytes_to_write
== 0)
256 memcpy(dest_buffer
, &data_
[data_read_cursor_
], bytes_to_write
);
257 data_read_cursor_
+= bytes_to_write
;
259 // Once all data has been consumed, transfer any file descriptors.
261 nacl_abi_size_t desc_count
= static_cast<nacl_abi_size_t
>(descs_
.size());
262 CHECK(desc_count
<= msg
->ndesc_length
);
263 msg
->ndesc_length
= desc_count
;
264 for (nacl_abi_size_t i
= 0; i
< desc_count
; i
++) {
265 // Copy the NaClDesc to the buffer and add a ref so it won't be freed
266 // when we clear our ScopedVector.
267 msg
->ndescv
[i
] = descs_
[i
]->desc();
268 NaClDescRef(descs_
[i
]->desc());
272 msg
->ndesc_length
= 0;
274 return static_cast<int>(bytes_to_write
);
277 NaClIPCAdapter::LockedData::LockedData()
278 : channel_closed_(false) {
281 NaClIPCAdapter::LockedData::~LockedData() {
284 NaClIPCAdapter::IOThreadData::IOThreadData() {
287 NaClIPCAdapter::IOThreadData::~IOThreadData() {
290 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle
& handle
,
291 base::TaskRunner
* runner
)
294 task_runner_(runner
),
296 io_thread_data_
.channel_
.reset(
297 new IPC::Channel(handle
, IPC::Channel::MODE_SERVER
, this));
298 // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did,
299 // and that task ran before this constructor completes, the reference count
300 // would go to 1 and then to 0 because of the Task, before we've been returned
301 // to the owning scoped_refptr, which is supposed to give us our first
305 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr
<IPC::Channel
> channel
,
306 base::TaskRunner
* runner
)
309 task_runner_(runner
),
311 io_thread_data_
.channel_
= channel
.Pass();
314 void NaClIPCAdapter::ConnectChannel() {
315 task_runner_
->PostTask(FROM_HERE
,
316 base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread
, this));
319 // Note that this message is controlled by the untrusted code. So we should be
320 // skeptical of anything it contains and quick to give up if anything is fishy.
321 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr
* msg
) {
322 if (msg
->iov_length
!= 1)
325 base::AutoLock
lock(lock_
);
327 const char* input_data
= static_cast<char*>(msg
->iov
[0].base
);
328 size_t input_data_len
= msg
->iov
[0].length
;
329 if (input_data_len
> IPC::Channel::kMaximumMessageSize
) {
334 // current_message[_len] refers to the total input data received so far.
335 const char* current_message
;
336 size_t current_message_len
;
337 bool did_append_input_data
;
338 if (locked_data_
.to_be_sent_
.empty()) {
339 // No accumulated data, we can avoid a copy by referring to the input
340 // buffer (the entire message fitting in one call is the common case).
341 current_message
= input_data
;
342 current_message_len
= input_data_len
;
343 did_append_input_data
= false;
345 // We've already accumulated some data, accumulate this new data and
346 // point to the beginning of the buffer.
348 // Make sure our accumulated message size doesn't overflow our max. Since
349 // we know that data_len < max size (checked above) and our current
350 // accumulated value is also < max size, we just need to make sure that
351 // 2x max size can never overflow.
352 COMPILE_ASSERT(IPC::Channel::kMaximumMessageSize
< (UINT_MAX
/ 2),
353 MaximumMessageSizeWillOverflow
);
354 size_t new_size
= locked_data_
.to_be_sent_
.size() + input_data_len
;
355 if (new_size
> IPC::Channel::kMaximumMessageSize
) {
360 locked_data_
.to_be_sent_
.append(input_data
, input_data_len
);
361 current_message
= &locked_data_
.to_be_sent_
[0];
362 current_message_len
= locked_data_
.to_be_sent_
.size();
363 did_append_input_data
= true;
366 // Check the total data we've accumulated so far to see if it contains a full
368 switch (GetBufferStatus(current_message
, current_message_len
)) {
369 case MESSAGE_IS_COMPLETE
: {
370 // Got a complete message, can send it out. This will be the common case.
371 bool success
= SendCompleteMessage(current_message
, current_message_len
);
373 return success
? static_cast<int>(input_data_len
) : -1;
375 case MESSAGE_IS_TRUNCATED
:
376 // For truncated messages, just accumulate the new data (if we didn't
377 // already do so above) and go back to waiting for more.
378 if (!did_append_input_data
)
379 locked_data_
.to_be_sent_
.append(input_data
, input_data_len
);
380 return static_cast<int>(input_data_len
);
381 case MESSAGE_HAS_EXTRA_DATA
:
383 // When the plugin gives us too much data, it's an error.
389 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr
* msg
) {
390 if (msg
->iov_length
!= 1)
395 base::AutoLock
lock(lock_
);
396 while (locked_data_
.to_be_received_
.empty() &&
397 !locked_data_
.channel_closed_
)
399 if (locked_data_
.channel_closed_
) {
402 retval
= LockedReceive(msg
);
410 void NaClIPCAdapter::CloseChannel() {
412 base::AutoLock
lock(lock_
);
413 locked_data_
.channel_closed_
= true;
417 task_runner_
->PostTask(FROM_HERE
,
418 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread
, this));
421 NaClDesc
* NaClIPCAdapter::MakeNaClDesc() {
422 return MakeNaClDescCustom(this);
425 #if defined(OS_POSIX)
426 int NaClIPCAdapter::TakeClientFileDescriptor() {
427 return io_thread_data_
.channel_
->TakeClientFileDescriptor();
431 #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \
432 case MESSAGE_TYPE::ID: { \
433 HandleConverter<MESSAGE_TYPE> extractor(&msg); \
434 if (!extractor.ConvertMessage(&handles, new_msg_ptr)) \
438 #define CASE_FOR_REPLY(MESSAGE_TYPE) \
439 case MESSAGE_TYPE::ID: { \
440 HandleConverter<MESSAGE_TYPE> extractor(&msg); \
441 if (!extractor.ConvertReply( \
443 static_cast<IPC::SyncMessage*>(new_msg_ptr))) \
448 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message
& msg
) {
450 base::AutoLock
lock(lock_
);
452 scoped_refptr
<RewrittenMessage
> rewritten_msg(new RewrittenMessage
);
454 // Pointer to the "new" message we will rewrite on Windows. On posix, this
455 // isn't necessary, so it will stay NULL.
456 IPC::Message
* new_msg_ptr
= NULL
;
457 IPC::Message
new_msg(msg
.routing_id(), msg
.type(), msg
.priority());
459 new_msg_ptr
= &new_msg
;
461 // Even on POSIX, we have to rewrite messages to create channels, because
462 // these contain a handle with an invalid (place holder) descriptor. The
463 // message sending code sees this and doesn't pass the descriptor over
465 if (msg
.type() == PpapiMsg_CreateNaClChannel::ID
)
466 new_msg_ptr
= &new_msg
;
470 switch (msg
.type()) {
471 CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel
)
472 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated
)
474 int id
= IPC::SyncMessage::GetMessageId(msg
);
475 LockedData::PendingSyncMsgMap::iterator
iter(
476 locked_data_
.pending_sync_msgs_
.find(id
));
477 if (iter
== locked_data_
.pending_sync_msgs_
.end()) {
481 uint32_t type
= iter
->second
;
482 locked_data_
.pending_sync_msgs_
.erase(iter
);
484 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer
)
485 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl
)
487 // Do nothing for messages we don't know.
493 // Do nothing for messages we don't know.
496 // Now add any descriptors we found to rewritten_msg. |handles| is usually
497 // empty, unless we read a message containing a FD or handle.
498 nacl::DescWrapperFactory factory
;
499 for (Handles::const_iterator iter
= handles
.begin();
500 iter
!= handles
.end();
502 scoped_ptr
<nacl::DescWrapper
> nacl_desc
;
503 switch (iter
->type()) {
504 case ppapi::proxy::SerializedHandle::SHARED_MEMORY
: {
505 const base::SharedMemoryHandle
& shm_handle
= iter
->shmem();
506 uint32_t size
= iter
->size();
507 nacl_desc
.reset(factory
.ImportShmHandle(
509 reinterpret_cast<const NaClHandle
>(shm_handle
),
513 static_cast<size_t>(size
)));
516 case ppapi::proxy::SerializedHandle::SOCKET
: {
517 nacl_desc
.reset(factory
.ImportSyncSocketHandle(
519 reinterpret_cast<const NaClHandle
>(iter
->descriptor())
521 iter
->descriptor().fd
526 case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE
: {
527 // Check that this came from a PpapiMsg_CreateNaClChannel message.
528 // This code here is only appropriate for that message.
529 DCHECK(msg
.type() == PpapiMsg_CreateNaClChannel::ID
);
530 IPC::ChannelHandle channel_handle
=
531 IPC::Channel::GenerateVerifiedChannelID("nacl");
532 scoped_refptr
<NaClIPCAdapter
> ipc_adapter(
533 new NaClIPCAdapter(channel_handle
, task_runner_
));
534 ipc_adapter
->ConnectChannel();
535 #if defined(OS_POSIX)
536 channel_handle
.socket
= base::FileDescriptor(
537 ipc_adapter
->TakeClientFileDescriptor(), true);
539 nacl_desc
.reset(factory
.MakeGeneric(ipc_adapter
->MakeNaClDesc()));
540 // Send back a message that the channel was created.
541 scoped_ptr
<IPC::Message
> response(
542 new PpapiHostMsg_ChannelCreated(channel_handle
));
543 task_runner_
->PostTask(FROM_HERE
,
544 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread
, this,
545 base::Passed(&response
)));
548 case ppapi::proxy::SerializedHandle::INVALID
: {
549 // Nothing to do. TODO(dmichael): Should we log this? Or is it
550 // sometimes okay to pass an INVALID handle?
553 // No default, so the compiler will warn us if new types get added.
556 rewritten_msg
->AddDescriptor(nacl_desc
.release());
558 if (new_msg_ptr
&& !handles
.empty())
559 SaveMessage(*new_msg_ptr
, rewritten_msg
.get());
561 SaveMessage(msg
, rewritten_msg
.get());
567 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid
) {
570 void NaClIPCAdapter::OnChannelError() {
574 NaClIPCAdapter::~NaClIPCAdapter() {
575 // Make sure the channel is deleted on the IO thread.
576 task_runner_
->PostTask(FROM_HERE
,
577 base::Bind(&DeleteChannel
, io_thread_data_
.channel_
.release()));
580 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr
* msg
) {
581 lock_
.AssertAcquired();
583 if (locked_data_
.to_be_received_
.empty())
585 scoped_refptr
<RewrittenMessage
> current
=
586 locked_data_
.to_be_received_
.front();
588 int retval
= current
->Read(msg
);
590 // When a message is entirely consumed, remove if from the waiting queue.
591 if (current
->is_consumed())
592 locked_data_
.to_be_received_
.pop();
597 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer
,
599 // The message will have already been validated, so we know it's large enough
601 const NaClMessageHeader
* header
=
602 reinterpret_cast<const NaClMessageHeader
*>(buffer
);
604 // Length of the message not including the body. The data passed to us by the
605 // plugin should match that in the message header. This should have already
606 // been validated by GetBufferStatus.
607 int body_len
= static_cast<int>(buffer_len
- sizeof(NaClMessageHeader
));
608 DCHECK(body_len
== static_cast<int>(header
->payload_size
));
610 // We actually discard the flags and only copy the ones we care about. This
611 // is just because message doesn't have a constructor that takes raw flags.
612 scoped_ptr
<IPC::Message
> msg(
613 new IPC::Message(header
->routing
, header
->type
,
614 IPC::Message::PRIORITY_NORMAL
));
615 if (header
->flags
& IPC::Message::SYNC_BIT
)
617 if (header
->flags
& IPC::Message::REPLY_BIT
)
619 if (header
->flags
& IPC::Message::REPLY_ERROR_BIT
)
620 msg
->set_reply_error();
621 if (header
->flags
& IPC::Message::UNBLOCK_BIT
)
622 msg
->set_unblock(true);
624 msg
->WriteBytes(&buffer
[sizeof(NaClMessageHeader
)], body_len
);
626 // Technically we didn't have to do any of the previous work in the lock. But
627 // sometimes our buffer will point to the to_be_sent_ string which is
628 // protected by the lock, and it's messier to factor Send() such that it can
629 // unlock for us. Holding the lock for the message construction, which is
630 // just some memcpys, shouldn't be a big deal.
631 lock_
.AssertAcquired();
632 if (locked_data_
.channel_closed_
)
633 return false; // TODO(brettw) clean up handles here when we add support!
635 // Store the type of all sync messages so that later we can translate the
636 // reply if necessary.
637 if (msg
->is_sync()) {
638 int id
= IPC::SyncMessage::GetMessageId(*msg
);
639 locked_data_
.pending_sync_msgs_
[id
] = msg
->type();
641 // Actual send must be done on the I/O thread.
642 task_runner_
->PostTask(FROM_HERE
,
643 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread
, this,
644 base::Passed(&msg
)));
648 void NaClIPCAdapter::ClearToBeSent() {
649 lock_
.AssertAcquired();
651 // Don't let the string keep its buffer behind our back.
653 locked_data_
.to_be_sent_
.swap(empty
);
656 void NaClIPCAdapter::ConnectChannelOnIOThread() {
657 if (!io_thread_data_
.channel_
->Connect())
661 void NaClIPCAdapter::CloseChannelOnIOThread() {
662 io_thread_data_
.channel_
->Close();
665 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr
<IPC::Message
> message
) {
666 io_thread_data_
.channel_
->Send(message
.release());
669 void NaClIPCAdapter::SaveMessage(const IPC::Message
& msg
,
670 RewrittenMessage
* rewritten_msg
) {
671 lock_
.AssertAcquired();
672 // There is some padding in this structure (the "padding" member is 16
673 // bits but this then gets padded to 32 bits). We want to be sure not to
674 // leak data to the untrusted plugin, so zero everything out first.
675 NaClMessageHeader header
;
676 memset(&header
, 0, sizeof(NaClMessageHeader
));
678 header
.payload_size
= static_cast<uint32
>(msg
.payload_size());
679 header
.routing
= msg
.routing_id();
680 header
.type
= msg
.type();
681 header
.flags
= msg
.flags();
682 header
.num_fds
= static_cast<int>(rewritten_msg
->desc_count());
684 rewritten_msg
->SetData(header
, msg
.payload(), msg
.payload_size());
685 locked_data_
.to_be_received_
.push(rewritten_msg
);