OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/nacl/nacl_ipc_adapter.h" | 5 #include "chrome/nacl/nacl_ipc_adapter.h" |
6 | 6 |
7 #include <limits.h> | 7 #include <limits.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 class NaClIPCAdapter::RewrittenMessage | 134 class NaClIPCAdapter::RewrittenMessage |
135 : public base::RefCounted<RewrittenMessage> { | 135 : public base::RefCounted<RewrittenMessage> { |
136 public: | 136 public: |
137 RewrittenMessage(); | 137 RewrittenMessage(); |
138 | 138 |
139 bool is_consumed() const { return data_read_cursor_ == data_len_; } | 139 bool is_consumed() const { return data_read_cursor_ == data_len_; } |
140 | 140 |
141 void SetData(const NaClIPCAdapter::NaClMessageHeader& header, | 141 void SetData(const NaClIPCAdapter::NaClMessageHeader& header, |
142 const void* payload, size_t payload_length); | 142 const void* payload, size_t payload_length); |
143 | 143 |
144 int Read(char* dest_buffer, size_t dest_buffer_size); | 144 int Read(NaClImcTypedMsgHdr* msg); |
| 145 |
| 146 void AddDescriptor(nacl::DescWrapper* desc) { descs_.push_back(desc); } |
| 147 |
| 148 size_t desc_count() const { return descs_.size(); } |
145 | 149 |
146 private: | 150 private: |
147 friend class base::RefCounted<RewrittenMessage>; | 151 friend class base::RefCounted<RewrittenMessage>; |
148 ~RewrittenMessage() {} | 152 ~RewrittenMessage() {} |
149 | 153 |
150 scoped_array<char> data_; | 154 scoped_array<char> data_; |
151 size_t data_len_; | 155 size_t data_len_; |
152 | 156 |
153 // Offset into data where the next read will happen. This will be equal to | 157 // Offset into data where the next read will happen. This will be equal to |
154 // data_len_ when all data has been consumed. | 158 // data_len_ when all data has been consumed. |
155 size_t data_read_cursor_; | 159 size_t data_read_cursor_; |
| 160 |
| 161 // Wrapped descriptors for transfer to untrusted code. |
| 162 ScopedVector<nacl::DescWrapper> descs_; |
156 }; | 163 }; |
157 | 164 |
158 NaClIPCAdapter::RewrittenMessage::RewrittenMessage() | 165 NaClIPCAdapter::RewrittenMessage::RewrittenMessage() |
159 : data_len_(0), | 166 : data_len_(0), |
160 data_read_cursor_(0) { | 167 data_read_cursor_(0) { |
161 } | 168 } |
162 | 169 |
163 void NaClIPCAdapter::RewrittenMessage::SetData( | 170 void NaClIPCAdapter::RewrittenMessage::SetData( |
164 const NaClIPCAdapter::NaClMessageHeader& header, | 171 const NaClIPCAdapter::NaClMessageHeader& header, |
165 const void* payload, | 172 const void* payload, |
166 size_t payload_length) { | 173 size_t payload_length) { |
167 DCHECK(!data_.get() && data_len_ == 0); | 174 DCHECK(!data_.get() && data_len_ == 0); |
168 size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader); | 175 size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader); |
169 data_len_ = header_len + payload_length; | 176 data_len_ = header_len + payload_length; |
170 data_.reset(new char[data_len_]); | 177 data_.reset(new char[data_len_]); |
171 | 178 |
172 memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader)); | 179 memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader)); |
173 memcpy(&data_[header_len], payload, payload_length); | 180 memcpy(&data_[header_len], payload, payload_length); |
174 } | 181 } |
175 | 182 |
176 int NaClIPCAdapter::RewrittenMessage::Read(char* dest_buffer, | 183 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr* msg) { |
177 size_t dest_buffer_size) { | |
178 CHECK(data_len_ >= data_read_cursor_); | 184 CHECK(data_len_ >= data_read_cursor_); |
| 185 char* dest_buffer = static_cast<char*>(msg->iov[0].base); |
| 186 size_t dest_buffer_size = msg->iov[0].length; |
179 size_t bytes_to_write = std::min(dest_buffer_size, | 187 size_t bytes_to_write = std::min(dest_buffer_size, |
180 data_len_ - data_read_cursor_); | 188 data_len_ - data_read_cursor_); |
181 if (bytes_to_write == 0) | 189 if (bytes_to_write == 0) |
182 return 0; | 190 return 0; |
183 | 191 |
184 memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write); | 192 memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write); |
185 data_read_cursor_ += bytes_to_write; | 193 data_read_cursor_ += bytes_to_write; |
| 194 |
| 195 // Once all data has been consumed, transfer any file descriptors. |
| 196 if (is_consumed()) { |
| 197 nacl_abi_size_t desc_count = static_cast<nacl_abi_size_t>(descs_.size()); |
| 198 CHECK(desc_count <= msg->ndesc_length); |
| 199 msg->ndesc_length = desc_count; |
| 200 for (nacl_abi_size_t i = 0; i < desc_count; i++) { |
| 201 // Copy the NaClDesc to the buffer and add a ref so it won't be freed |
| 202 // when we clear our ScopedVector. |
| 203 msg->ndescv[i] = descs_[i]->desc(); |
| 204 NaClDescRef(descs_[i]->desc()); |
| 205 } |
| 206 descs_.clear(); |
| 207 } |
186 return static_cast<int>(bytes_to_write); | 208 return static_cast<int>(bytes_to_write); |
187 } | 209 } |
188 | 210 |
189 NaClIPCAdapter::LockedData::LockedData() | 211 NaClIPCAdapter::LockedData::LockedData() |
190 : channel_closed_(false) { | 212 : channel_closed_(false) { |
191 } | 213 } |
192 | 214 |
193 NaClIPCAdapter::LockedData::~LockedData() { | 215 NaClIPCAdapter::LockedData::~LockedData() { |
194 } | 216 } |
195 | 217 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 // When the plugin gives us too much data, it's an error. | 309 // When the plugin gives us too much data, it's an error. |
288 ClearToBeSent(); | 310 ClearToBeSent(); |
289 return -1; | 311 return -1; |
290 } | 312 } |
291 } | 313 } |
292 | 314 |
293 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) { | 315 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) { |
294 if (msg->iov_length != 1) | 316 if (msg->iov_length != 1) |
295 return -1; | 317 return -1; |
296 | 318 |
297 char* output_buffer = static_cast<char*>(msg->iov[0].base); | |
298 size_t output_buffer_size = msg->iov[0].length; | |
299 int retval = 0; | 319 int retval = 0; |
300 { | 320 { |
301 base::AutoLock lock(lock_); | 321 base::AutoLock lock(lock_); |
302 while (locked_data_.to_be_received_.empty() && | 322 while (locked_data_.to_be_received_.empty() && |
303 !locked_data_.channel_closed_) | 323 !locked_data_.channel_closed_) |
304 cond_var_.Wait(); | 324 cond_var_.Wait(); |
305 if (locked_data_.channel_closed_) { | 325 if (locked_data_.channel_closed_) { |
306 retval = -1; | 326 retval = -1; |
307 } else { | 327 } else { |
308 retval = LockedReceive(output_buffer, output_buffer_size); | 328 retval = LockedReceive(msg); |
309 DCHECK(retval > 0); | 329 DCHECK(retval > 0); |
310 } | 330 } |
311 int desc_count = static_cast<int>(locked_data_.nacl_descs_.size()); | |
312 CHECK(desc_count <= NACL_ABI_IMC_DESC_MAX); | |
313 msg->ndesc_length = desc_count; | |
314 for (int i = 0; i < desc_count; i++) | |
315 msg->ndescv[i] = locked_data_.nacl_descs_[i]->desc(); | |
316 } | 331 } |
317 cond_var_.Signal(); | 332 cond_var_.Signal(); |
318 return retval; | 333 return retval; |
319 } | 334 } |
320 | 335 |
321 void NaClIPCAdapter::CloseChannel() { | 336 void NaClIPCAdapter::CloseChannel() { |
322 { | 337 { |
323 base::AutoLock lock(lock_); | 338 base::AutoLock lock(lock_); |
324 locked_data_.channel_closed_ = true; | 339 locked_data_.channel_closed_ = true; |
325 } | 340 } |
326 cond_var_.Signal(); | 341 cond_var_.Signal(); |
327 | 342 |
328 task_runner_->PostTask(FROM_HERE, | 343 task_runner_->PostTask(FROM_HERE, |
329 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this)); | 344 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this)); |
330 } | 345 } |
331 | 346 |
332 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { | 347 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { |
333 return MakeNaClDescCustom(this); | 348 return MakeNaClDescCustom(this); |
334 } | 349 } |
335 | 350 |
336 #if defined(OS_POSIX) | 351 #if defined(OS_POSIX) |
337 int NaClIPCAdapter::TakeClientFileDescriptor() { | 352 int NaClIPCAdapter::TakeClientFileDescriptor() { |
338 return io_thread_data_.channel_->TakeClientFileDescriptor(); | 353 return io_thread_data_.channel_->TakeClientFileDescriptor(); |
339 } | 354 } |
340 #endif | 355 #endif |
341 | 356 |
342 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& message) { | 357 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) { |
343 { | 358 { |
344 base::AutoLock lock(lock_); | 359 base::AutoLock lock(lock_); |
345 | 360 |
346 // Clear any descriptors left from the prior message. | 361 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage); |
347 locked_data_.nacl_descs_.clear(); | |
348 | 362 |
349 PickleIterator it(message); | 363 PickleIterator it(msg); |
350 switch (message.type()) { | 364 switch (msg.type()) { |
351 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { | 365 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { |
352 int instance_id; | 366 int instance_id; |
353 int resource_id; | 367 int resource_id; |
354 int result_code; | 368 int result_code; |
355 NaClHandle sock_handle; | 369 NaClHandle sock_handle; |
356 NaClHandle shm_handle; | 370 NaClHandle shm_handle; |
357 uint32_t shm_length; | 371 uint32_t shm_length; |
358 if (ReadHostResource(&it, &instance_id, &resource_id) && | 372 if (ReadHostResource(&it, &instance_id, &resource_id) && |
359 it.ReadInt(&result_code) && | 373 it.ReadInt(&result_code) && |
360 ReadFileDescriptor(message, &it, &sock_handle) && | 374 ReadFileDescriptor(msg, &it, &sock_handle) && |
361 ReadFileDescriptor(message, &it, &shm_handle) && | 375 ReadFileDescriptor(msg, &it, &shm_handle) && |
362 it.ReadUInt32(&shm_length)) { | 376 it.ReadUInt32(&shm_length)) { |
363 // Our caller, OnMessageReceived, holds the lock for locked_data_. | 377 // Import the sync socket. |
364 // Import the sync socket. Use DescWrappers to simplify clean up. | |
365 nacl::DescWrapperFactory factory; | 378 nacl::DescWrapperFactory factory; |
366 scoped_ptr<nacl::DescWrapper> socket_wrapper( | 379 scoped_ptr<nacl::DescWrapper> socket_wrapper( |
367 factory.ImportSyncSocketHandle(sock_handle)); | 380 factory.ImportSyncSocketHandle(sock_handle)); |
368 // Import the shared memory handle and increase its size by 4 bytes to | 381 // Import the shared memory handle and increase its size by 4 bytes to |
369 // accommodate the length data we write to signal the host. | 382 // accommodate the length data we write at the end to signal the host. |
370 scoped_ptr<nacl::DescWrapper> shm_wrapper( | 383 scoped_ptr<nacl::DescWrapper> shm_wrapper( |
371 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); | 384 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); |
372 if (shm_wrapper.get() && socket_wrapper.get()) { | 385 if (shm_wrapper.get() && socket_wrapper.get()) { |
373 locked_data_.nacl_descs_.push_back(socket_wrapper.release()); | 386 rewritten_msg->AddDescriptor(socket_wrapper.release()); |
374 locked_data_.nacl_descs_.push_back(shm_wrapper.release()); | 387 rewritten_msg->AddDescriptor(shm_wrapper.release()); |
375 } | 388 } |
376 #if defined(OS_POSIX) | 389 #if defined(OS_POSIX) |
377 SaveMessage(message); | 390 SaveMessage(msg, rewritten_msg.get()); |
378 #else // defined(OS_POSIX) | 391 #else |
379 // On Windows we must rewrite the message to the POSIX representation. | 392 // On Windows we must rewrite the message to match the POSIX form. |
380 IPC::Message new_msg(message.routing_id(), | 393 IPC::Message new_msg(msg.routing_id(), |
381 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, | 394 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, |
382 message.priority()); | 395 msg.priority()); |
383 WriteHostResource(&new_msg, instance_id, resource_id); | 396 WriteHostResource(&new_msg, instance_id, resource_id); |
384 new_msg.WriteInt(result_code); | 397 new_msg.WriteInt(result_code); |
385 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 | 398 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 |
386 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 | 399 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 |
387 new_msg.WriteUInt32(shm_length); | 400 new_msg.WriteUInt32(shm_length); |
388 SaveMessage(new_msg); | 401 SaveMessage(new_msg, rewritten_msg.get()); |
389 #endif | 402 #endif |
390 } | 403 } |
391 break; | 404 break; |
392 } | 405 } |
393 default: { | 406 default: { |
394 SaveMessage(message); | 407 SaveMessage(msg, rewritten_msg.get()); |
395 } | 408 } |
396 } | 409 } |
397 } | 410 } |
398 cond_var_.Signal(); | 411 cond_var_.Signal(); |
399 return true; | 412 return true; |
400 } | 413 } |
401 | 414 |
402 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { | 415 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { |
403 } | 416 } |
404 | 417 |
405 void NaClIPCAdapter::OnChannelError() { | 418 void NaClIPCAdapter::OnChannelError() { |
406 CloseChannel(); | 419 CloseChannel(); |
407 } | 420 } |
408 | 421 |
409 NaClIPCAdapter::~NaClIPCAdapter() { | 422 NaClIPCAdapter::~NaClIPCAdapter() { |
410 // Make sure the channel is deleted on the IO thread. | 423 // Make sure the channel is deleted on the IO thread. |
411 task_runner_->PostTask(FROM_HERE, | 424 task_runner_->PostTask(FROM_HERE, |
412 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); | 425 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); |
413 } | 426 } |
414 | 427 |
415 int NaClIPCAdapter::LockedReceive(char* output_buffer, | 428 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) { |
416 size_t output_buffer_size) { | |
417 lock_.AssertAcquired(); | 429 lock_.AssertAcquired(); |
418 | 430 |
419 if (locked_data_.to_be_received_.empty()) | 431 if (locked_data_.to_be_received_.empty()) |
420 return 0; | 432 return 0; |
421 scoped_refptr<RewrittenMessage> current = | 433 scoped_refptr<RewrittenMessage> current = |
422 locked_data_.to_be_received_.front(); | 434 locked_data_.to_be_received_.front(); |
423 | 435 |
424 int retval = current->Read(output_buffer, output_buffer_size); | 436 int retval = current->Read(msg); |
425 | 437 |
426 // When a message is entirely consumed, remove if from the waiting queue. | 438 // When a message is entirely consumed, remove if from the waiting queue. |
427 if (current->is_consumed()) | 439 if (current->is_consumed()) |
428 locked_data_.to_be_received_.pop(); | 440 locked_data_.to_be_received_.pop(); |
| 441 |
429 return retval; | 442 return retval; |
430 } | 443 } |
431 | 444 |
432 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, | 445 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, |
433 size_t buffer_len) { | 446 size_t buffer_len) { |
434 // The message will have already been validated, so we know it's large enough | 447 // The message will have already been validated, so we know it's large enough |
435 // for our header. | 448 // for our header. |
436 const NaClMessageHeader* header = | 449 const NaClMessageHeader* header = |
437 reinterpret_cast<const NaClMessageHeader*>(buffer); | 450 reinterpret_cast<const NaClMessageHeader*>(buffer); |
438 | 451 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 } | 501 } |
489 | 502 |
490 void NaClIPCAdapter::CloseChannelOnIOThread() { | 503 void NaClIPCAdapter::CloseChannelOnIOThread() { |
491 io_thread_data_.channel_->Close(); | 504 io_thread_data_.channel_->Close(); |
492 } | 505 } |
493 | 506 |
494 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { | 507 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { |
495 io_thread_data_.channel_->Send(message.release()); | 508 io_thread_data_.channel_->Send(message.release()); |
496 } | 509 } |
497 | 510 |
498 void NaClIPCAdapter::SaveMessage(const IPC::Message& message) { | 511 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg, |
| 512 RewrittenMessage* rewritten_msg) { |
| 513 lock_.AssertAcquired(); |
499 // There is some padding in this structure (the "padding" member is 16 | 514 // There is some padding in this structure (the "padding" member is 16 |
500 // bits but this then gets padded to 32 bits). We want to be sure not to | 515 // bits but this then gets padded to 32 bits). We want to be sure not to |
501 // leak data to the untrusted plugin, so zero everything out first. | 516 // leak data to the untrusted plugin, so zero everything out first. |
502 NaClMessageHeader header; | 517 NaClMessageHeader header; |
503 memset(&header, 0, sizeof(NaClMessageHeader)); | 518 memset(&header, 0, sizeof(NaClMessageHeader)); |
504 | 519 |
505 header.payload_size = static_cast<uint32>(message.payload_size()); | 520 header.payload_size = static_cast<uint32>(msg.payload_size()); |
506 header.routing = message.routing_id(); | 521 header.routing = msg.routing_id(); |
507 header.type = message.type(); | 522 header.type = msg.type(); |
508 header.flags = message.flags(); | 523 header.flags = msg.flags(); |
509 header.num_fds = static_cast<int>(locked_data_.nacl_descs_.size()); | 524 header.num_fds = static_cast<int>(rewritten_msg->desc_count()); |
510 | 525 |
511 scoped_refptr<RewrittenMessage> dest(new RewrittenMessage); | 526 rewritten_msg->SetData(header, msg.payload(), msg.payload_size()); |
512 dest->SetData(header, message.payload(), message.payload_size()); | 527 locked_data_.to_be_received_.push(rewritten_msg); |
513 locked_data_.to_be_received_.push(dest); | |
514 } | 528 } |
515 | 529 |
OLD | NEW |