Chromium Code Reviews| 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 TransferData(NaClImcTypedMsgHdr* msg); |
| 145 | |
| 146 void AddDescriptor(nacl::DescWrapper* desc) { descs_.push_back(desc); } | |
| 147 | |
| 148 int desc_count() const { return static_cast<int>(descs_.size()); } | |
|
dmichael (off chromium)
2012/07/25 16:00:40
why not just use size_t for the return type?
bbudge
2012/07/25 16:54:14
Done.
| |
| 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::TransferData(NaClImcTypedMsgHdr* msg) { |
|
dmichael (off chromium)
2012/07/25 16:00:40
I think I liked |Read| better for the name. It's n
bbudge
2012/07/25 16:54:14
I was finding 'Read' to be confusing. But 2 agains
| |
| 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(); | 362 locked_data_.to_be_received_.push(rewritten_msg); |
|
dmichael (off chromium)
2012/07/25 16:00:40
Should this part maybe be at the end of SaveMessag
bbudge
2012/07/25 16:54:14
Good idea. Done.
| |
| 348 | 363 |
| 349 PickleIterator it(message); | 364 PickleIterator it(msg); |
| 350 switch (message.type()) { | 365 switch (msg.type()) { |
| 351 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { | 366 case PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID: { |
| 352 int instance_id; | 367 int instance_id; |
| 353 int resource_id; | 368 int resource_id; |
| 354 int result_code; | 369 int result_code; |
| 355 NaClHandle sock_handle; | 370 NaClHandle sock_handle; |
| 356 NaClHandle shm_handle; | 371 NaClHandle shm_handle; |
| 357 uint32_t shm_length; | 372 uint32_t shm_length; |
| 358 if (ReadHostResource(&it, &instance_id, &resource_id) && | 373 if (ReadHostResource(&it, &instance_id, &resource_id) && |
| 359 it.ReadInt(&result_code) && | 374 it.ReadInt(&result_code) && |
| 360 ReadFileDescriptor(message, &it, &sock_handle) && | 375 ReadFileDescriptor(msg, &it, &sock_handle) && |
| 361 ReadFileDescriptor(message, &it, &shm_handle) && | 376 ReadFileDescriptor(msg, &it, &shm_handle) && |
| 362 it.ReadUInt32(&shm_length)) { | 377 it.ReadUInt32(&shm_length)) { |
| 363 // Our caller, OnMessageReceived, holds the lock for locked_data_. | 378 // Import the sync socket. |
| 364 // Import the sync socket. Use DescWrappers to simplify clean up. | |
| 365 nacl::DescWrapperFactory factory; | 379 nacl::DescWrapperFactory factory; |
| 366 scoped_ptr<nacl::DescWrapper> socket_wrapper( | 380 scoped_ptr<nacl::DescWrapper> socket_wrapper( |
| 367 factory.ImportSyncSocketHandle(sock_handle)); | 381 factory.ImportSyncSocketHandle(sock_handle)); |
| 368 // Import the shared memory handle and increase its size by 4 bytes to | 382 // Import the shared memory handle and increase its size by 4 bytes to |
| 369 // accommodate the length data we write to signal the host. | 383 // accommodate the length data we write at the end to signal the host. |
| 370 scoped_ptr<nacl::DescWrapper> shm_wrapper( | 384 scoped_ptr<nacl::DescWrapper> shm_wrapper( |
| 371 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); | 385 factory.ImportShmHandle(shm_handle, shm_length + sizeof(uint32))); |
| 372 if (shm_wrapper.get() && socket_wrapper.get()) { | 386 if (shm_wrapper.get() && socket_wrapper.get()) { |
| 373 locked_data_.nacl_descs_.push_back(socket_wrapper.release()); | 387 rewritten_msg->AddDescriptor(socket_wrapper.release()); |
| 374 locked_data_.nacl_descs_.push_back(shm_wrapper.release()); | 388 rewritten_msg->AddDescriptor(shm_wrapper.release()); |
| 375 } | 389 } |
| 376 #if defined(OS_POSIX) | 390 #if defined(OS_POSIX) |
| 377 SaveMessage(message); | 391 SaveMessage(msg, rewritten_msg.get()); |
| 378 #else // defined(OS_POSIX) | 392 #else |
| 379 // On Windows we must rewrite the message to the POSIX representation. | 393 // On Windows we must rewrite the message to match the POSIX form. |
| 380 IPC::Message new_msg(message.routing_id(), | 394 IPC::Message new_msg(msg.routing_id(), |
| 381 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, | 395 PpapiMsg_PPBAudio_NotifyAudioStreamCreated::ID, |
| 382 message.priority()); | 396 msg.priority()); |
| 383 WriteHostResource(&new_msg, instance_id, resource_id); | 397 WriteHostResource(&new_msg, instance_id, resource_id); |
| 384 new_msg.WriteInt(result_code); | 398 new_msg.WriteInt(result_code); |
| 385 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 | 399 WriteFileDescriptor(&new_msg, 0); // socket handle, index = 0 |
| 386 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 | 400 WriteFileDescriptor(&new_msg, 1); // shm handle, index = 1 |
| 387 new_msg.WriteUInt32(shm_length); | 401 new_msg.WriteUInt32(shm_length); |
| 388 SaveMessage(new_msg); | 402 SaveMessage(new_msg, rewritten_msg.get()); |
| 389 #endif | 403 #endif |
| 390 } | 404 } |
| 391 break; | 405 break; |
| 392 } | 406 } |
| 393 default: { | 407 default: { |
| 394 SaveMessage(message); | 408 SaveMessage(msg, rewritten_msg.get()); |
| 395 } | 409 } |
| 396 } | 410 } |
| 397 } | 411 } |
| 398 cond_var_.Signal(); | 412 cond_var_.Signal(); |
| 399 return true; | 413 return true; |
| 400 } | 414 } |
| 401 | 415 |
| 402 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { | 416 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { |
| 403 } | 417 } |
| 404 | 418 |
| 405 void NaClIPCAdapter::OnChannelError() { | 419 void NaClIPCAdapter::OnChannelError() { |
| 406 CloseChannel(); | 420 CloseChannel(); |
| 407 } | 421 } |
| 408 | 422 |
| 409 NaClIPCAdapter::~NaClIPCAdapter() { | 423 NaClIPCAdapter::~NaClIPCAdapter() { |
| 410 // Make sure the channel is deleted on the IO thread. | 424 // Make sure the channel is deleted on the IO thread. |
| 411 task_runner_->PostTask(FROM_HERE, | 425 task_runner_->PostTask(FROM_HERE, |
| 412 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); | 426 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); |
| 413 } | 427 } |
| 414 | 428 |
| 415 int NaClIPCAdapter::LockedReceive(char* output_buffer, | 429 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) { |
| 416 size_t output_buffer_size) { | |
| 417 lock_.AssertAcquired(); | 430 lock_.AssertAcquired(); |
| 418 | 431 |
| 419 if (locked_data_.to_be_received_.empty()) | 432 if (locked_data_.to_be_received_.empty()) |
| 420 return 0; | 433 return 0; |
| 421 scoped_refptr<RewrittenMessage> current = | 434 scoped_refptr<RewrittenMessage> current = |
| 422 locked_data_.to_be_received_.front(); | 435 locked_data_.to_be_received_.front(); |
| 423 | 436 |
| 424 int retval = current->Read(output_buffer, output_buffer_size); | 437 int retval = current->TransferData(msg); |
| 425 | 438 |
| 426 // When a message is entirely consumed, remove if from the waiting queue. | 439 // When a message is entirely consumed, remove if from the waiting queue. |
| 427 if (current->is_consumed()) | 440 if (current->is_consumed()) |
| 428 locked_data_.to_be_received_.pop(); | 441 locked_data_.to_be_received_.pop(); |
| 442 | |
| 429 return retval; | 443 return retval; |
| 430 } | 444 } |
| 431 | 445 |
| 432 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, | 446 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, |
| 433 size_t buffer_len) { | 447 size_t buffer_len) { |
| 434 // The message will have already been validated, so we know it's large enough | 448 // The message will have already been validated, so we know it's large enough |
| 435 // for our header. | 449 // for our header. |
| 436 const NaClMessageHeader* header = | 450 const NaClMessageHeader* header = |
| 437 reinterpret_cast<const NaClMessageHeader*>(buffer); | 451 reinterpret_cast<const NaClMessageHeader*>(buffer); |
| 438 | 452 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 488 } | 502 } |
| 489 | 503 |
| 490 void NaClIPCAdapter::CloseChannelOnIOThread() { | 504 void NaClIPCAdapter::CloseChannelOnIOThread() { |
| 491 io_thread_data_.channel_->Close(); | 505 io_thread_data_.channel_->Close(); |
| 492 } | 506 } |
| 493 | 507 |
| 494 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { | 508 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { |
| 495 io_thread_data_.channel_->Send(message.release()); | 509 io_thread_data_.channel_->Send(message.release()); |
| 496 } | 510 } |
| 497 | 511 |
| 498 void NaClIPCAdapter::SaveMessage(const IPC::Message& message) { | 512 void NaClIPCAdapter::SaveMessage(const IPC::Message& message, |
| 513 RewrittenMessage* rewritten_message) { | |
| 514 lock_.AssertAcquired(); | |
| 499 // There is some padding in this structure (the "padding" member is 16 | 515 // 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 | 516 // 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. | 517 // leak data to the untrusted plugin, so zero everything out first. |
| 502 NaClMessageHeader header; | 518 NaClMessageHeader header; |
| 503 memset(&header, 0, sizeof(NaClMessageHeader)); | 519 memset(&header, 0, sizeof(NaClMessageHeader)); |
| 504 | 520 |
| 505 header.payload_size = static_cast<uint32>(message.payload_size()); | 521 header.payload_size = static_cast<uint32>(message.payload_size()); |
| 506 header.routing = message.routing_id(); | 522 header.routing = message.routing_id(); |
| 507 header.type = message.type(); | 523 header.type = message.type(); |
| 508 header.flags = message.flags(); | 524 header.flags = message.flags(); |
| 509 header.num_fds = static_cast<int>(locked_data_.nacl_descs_.size()); | 525 header.num_fds = rewritten_message->desc_count(); |
| 510 | 526 |
| 511 scoped_refptr<RewrittenMessage> dest(new RewrittenMessage); | 527 rewritten_message->SetData(header, message.payload(), message.payload_size()); |
| 512 dest->SetData(header, message.payload(), message.payload_size()); | |
| 513 locked_data_.to_be_received_.push(dest); | |
| 514 } | 528 } |
| 515 | 529 |
| OLD | NEW |