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 "ipc/ipc_channel_posix.h" | 5 #include "ipc/ipc_channel_posix.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <stddef.h> | 9 #include <stddef.h> |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 true, | 340 true, |
341 base::MessageLoopForIO::WATCH_READ, | 341 base::MessageLoopForIO::WATCH_READ, |
342 &server_listen_connection_watcher_, | 342 &server_listen_connection_watcher_, |
343 this); | 343 this); |
344 } else { | 344 } else { |
345 did_connect = AcceptConnection(); | 345 did_connect = AcceptConnection(); |
346 } | 346 } |
347 return did_connect; | 347 return did_connect; |
348 } | 348 } |
349 | 349 |
350 void Channel::ChannelImpl::CloseFileDescriptors(Message* msg) { | |
351 #if 0 // defined(OS_MACOSX) // Disable fix to make sure test works | |
352 // There is a bug on OSX which makes it dangerous to close | |
353 // a file descriptor while it is in transit. So instead we | |
354 // store the file descriptor in a set and send a message to | |
355 // the recipient, which is queued AFTER the message that | |
356 // sent the FD. The recipient will reply to the message, | |
357 // letting us know that it is now safe to close the file | |
358 // descptor. For more information, see: | |
Scott Hess - ex-Googler
2013/10/09 20:18:33
descriptor
hubbe
2013/10/09 21:34:12
Done.
| |
359 // http://crbug.com/298276 | |
360 std::vector<int> to_close; | |
361 msg->file_descriptor_set()->GetFDsToCloseAndClear(&to_close); | |
362 for (size_t i = 0; i < to_close.size(); i++) { | |
363 fds_to_close_.insert(to_close[i]); | |
364 QueueCloseFDMessage(to_close[i], 2); | |
365 } | |
366 #else | |
367 msg->file_descriptor_set()->CommitAll(); | |
368 #endif | |
369 } | |
370 | |
371 | |
350 bool Channel::ChannelImpl::ProcessOutgoingMessages() { | 372 bool Channel::ChannelImpl::ProcessOutgoingMessages() { |
351 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | 373 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's |
352 // no connection? | 374 // no connection? |
353 if (output_queue_.empty()) | 375 if (output_queue_.empty()) |
354 return true; | 376 return true; |
355 | 377 |
356 if (pipe_ == -1) | 378 if (pipe_ == -1) |
357 return false; | 379 return false; |
358 | 380 |
359 // Write out all the messages we can till the write blocks or there are no | 381 // Write out all the messages we can till the write blocks or there are no |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 // Only the Hello message sends the file descriptor with the message. | 434 // Only the Hello message sends the file descriptor with the message. |
413 // Subsequently, we can send file descriptors on the dedicated | 435 // Subsequently, we can send file descriptors on the dedicated |
414 // fd_pipe_ which makes Seccomp sandbox operation more efficient. | 436 // fd_pipe_ which makes Seccomp sandbox operation more efficient. |
415 struct iovec fd_pipe_iov = { const_cast<char *>(""), 1 }; | 437 struct iovec fd_pipe_iov = { const_cast<char *>(""), 1 }; |
416 msgh.msg_iov = &fd_pipe_iov; | 438 msgh.msg_iov = &fd_pipe_iov; |
417 fd_written = fd_pipe_; | 439 fd_written = fd_pipe_; |
418 bytes_written = HANDLE_EINTR(sendmsg(fd_pipe_, &msgh, MSG_DONTWAIT)); | 440 bytes_written = HANDLE_EINTR(sendmsg(fd_pipe_, &msgh, MSG_DONTWAIT)); |
419 msgh.msg_iov = &iov; | 441 msgh.msg_iov = &iov; |
420 msgh.msg_controllen = 0; | 442 msgh.msg_controllen = 0; |
421 if (bytes_written > 0) { | 443 if (bytes_written > 0) { |
422 msg->file_descriptor_set()->CommitAll(); | 444 CloseFileDescriptors(msg); |
423 } | 445 } |
424 } | 446 } |
425 #endif // IPC_USES_READWRITE | 447 #endif // IPC_USES_READWRITE |
426 } | 448 } |
427 | 449 |
428 if (bytes_written == 1) { | 450 if (bytes_written == 1) { |
429 fd_written = pipe_; | 451 fd_written = pipe_; |
430 #if defined(IPC_USES_READWRITE) | 452 #if defined(IPC_USES_READWRITE) |
431 if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(*msg)) { | 453 if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(*msg)) { |
432 DCHECK_EQ(msg->file_descriptor_set()->size(), 1U); | 454 DCHECK_EQ(msg->file_descriptor_set()->size(), 1U); |
433 } | 455 } |
434 if (!msgh.msg_controllen) { | 456 if (!msgh.msg_controllen) { |
435 bytes_written = HANDLE_EINTR(write(pipe_, out_bytes, amt_to_write)); | 457 bytes_written = HANDLE_EINTR(write(pipe_, out_bytes, amt_to_write)); |
436 } else | 458 } else |
437 #endif // IPC_USES_READWRITE | 459 #endif // IPC_USES_READWRITE |
438 { | 460 { |
439 bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT)); | 461 bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT)); |
440 } | 462 } |
441 } | 463 } |
442 if (bytes_written > 0) | 464 if (bytes_written > 0) |
443 msg->file_descriptor_set()->CommitAll(); | 465 CloseFileDescriptors(msg); |
444 | 466 |
445 if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) { | 467 if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) { |
446 #if defined(OS_MACOSX) | 468 #if defined(OS_MACOSX) |
447 // On OSX writing to a pipe with no listener returns EPERM. | 469 // On OSX writing to a pipe with no listener returns EPERM. |
448 if (errno == EPERM) { | 470 if (errno == EPERM) { |
449 Close(); | 471 Close(); |
450 return false; | 472 return false; |
451 } | 473 } |
452 #endif // OS_MACOSX | 474 #endif // OS_MACOSX |
453 if (errno == EPIPE) { | 475 if (errno == EPIPE) { |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
568 #endif // IPC_USES_READWRITE | 590 #endif // IPC_USES_READWRITE |
569 | 591 |
570 while (!output_queue_.empty()) { | 592 while (!output_queue_.empty()) { |
571 Message* m = output_queue_.front(); | 593 Message* m = output_queue_.front(); |
572 output_queue_.pop(); | 594 output_queue_.pop(); |
573 delete m; | 595 delete m; |
574 } | 596 } |
575 | 597 |
576 // Close any outstanding, received file descriptors. | 598 // Close any outstanding, received file descriptors. |
577 ClearInputFDs(); | 599 ClearInputFDs(); |
600 | |
601 #if defined(OS_MACOSX) | |
602 // Clear any outstanding, sent file descriptors. | |
603 for (std::set<int>::iterator i = fds_to_close_.begin(); | |
604 i != fds_to_close_.end(); | |
605 ++i) { | |
606 if (HANDLE_EINTR(close(*i)) < 0) | |
607 PLOG(ERROR) << "close"; | |
608 } | |
609 #endif | |
578 } | 610 } |
579 | 611 |
580 // static | 612 // static |
581 bool Channel::ChannelImpl::IsNamedServerInitialized( | 613 bool Channel::ChannelImpl::IsNamedServerInitialized( |
582 const std::string& channel_id) { | 614 const std::string& channel_id) { |
583 return base::PathExists(base::FilePath(channel_id)); | 615 return base::PathExists(base::FilePath(channel_id)); |
584 } | 616 } |
585 | 617 |
586 #if defined(OS_LINUX) | 618 #if defined(OS_LINUX) |
587 // static | 619 // static |
588 void Channel::ChannelImpl::SetGlobalPid(int pid) { | 620 void Channel::ChannelImpl::SetGlobalPid(int pid) { |
589 global_pid_ = pid; | 621 global_pid_ = pid; |
590 } | 622 } |
591 #endif // OS_LINUX | 623 #endif // OS_LINUX |
592 | 624 |
593 // Called by libevent when we can read from the pipe without blocking. | 625 // Called by libevent when we can read from the pipe without blocking. |
594 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { | 626 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { |
595 bool send_server_hello_msg = false; | |
596 if (fd == server_listen_pipe_) { | 627 if (fd == server_listen_pipe_) { |
597 int new_pipe = 0; | 628 int new_pipe = 0; |
598 if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) || | 629 if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) || |
599 new_pipe < 0) { | 630 new_pipe < 0) { |
600 Close(); | 631 Close(); |
601 listener()->OnChannelListenError(); | 632 listener()->OnChannelListenError(); |
602 } | 633 } |
603 | 634 |
604 if (pipe_ != -1) { | 635 if (pipe_ != -1) { |
605 // We already have a connection. We only handle one at a time. | 636 // We already have a connection. We only handle one at a time. |
(...skipping 18 matching lines...) Expand all Loading... | |
624 if (client_euid != geteuid()) { | 655 if (client_euid != geteuid()) { |
625 DLOG(WARNING) << "Client euid is not authorised"; | 656 DLOG(WARNING) << "Client euid is not authorised"; |
626 ResetToAcceptingConnectionState(); | 657 ResetToAcceptingConnectionState(); |
627 return; | 658 return; |
628 } | 659 } |
629 } | 660 } |
630 | 661 |
631 if (!AcceptConnection()) { | 662 if (!AcceptConnection()) { |
632 NOTREACHED() << "AcceptConnection should not fail on server"; | 663 NOTREACHED() << "AcceptConnection should not fail on server"; |
633 } | 664 } |
634 send_server_hello_msg = true; | |
635 waiting_connect_ = false; | 665 waiting_connect_ = false; |
636 } else if (fd == pipe_) { | 666 } else if (fd == pipe_) { |
637 if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) { | 667 if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) { |
638 send_server_hello_msg = true; | |
639 waiting_connect_ = false; | 668 waiting_connect_ = false; |
640 } | 669 } |
641 if (!ProcessIncomingMessages()) { | 670 if (!ProcessIncomingMessages()) { |
642 // ClosePipeOnError may delete this object, so we mustn't call | 671 // ClosePipeOnError may delete this object, so we mustn't call |
643 // ProcessOutgoingMessages. | 672 // ProcessOutgoingMessages. |
644 send_server_hello_msg = false; | |
645 ClosePipeOnError(); | 673 ClosePipeOnError(); |
674 return; | |
646 } | 675 } |
647 } else { | 676 } else { |
648 NOTREACHED() << "Unknown pipe " << fd; | 677 NOTREACHED() << "Unknown pipe " << fd; |
649 } | 678 } |
650 | 679 |
651 // If we're a server and handshaking, then we want to make sure that we | 680 // If we're a server and handshaking, then we want to make sure that we |
652 // only send our handshake message after we've processed the client's. | 681 // only send our handshake message after we've processed the client's. |
653 // This gives us a chance to kill the client if the incoming handshake | 682 // This gives us a chance to kill the client if the incoming handshake |
654 // is invalid. | 683 // is invalid. This also flushes any closefd messagse. |
655 if (send_server_hello_msg) { | 684 if (!is_blocked_on_write_) { |
Scott Hess - ex-Googler
2013/10/09 20:18:33
I am nowhere close to understanding whether the ch
hubbe
2013/10/09 21:34:12
It's fairly easy to reason out:
When we enter OnF
| |
656 ProcessOutgoingMessages(); | 685 ProcessOutgoingMessages(); |
657 } | 686 } |
658 } | 687 } |
659 | 688 |
660 // Called by libevent when we can write to the pipe without blocking. | 689 // Called by libevent when we can write to the pipe without blocking. |
661 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { | 690 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { |
662 DCHECK_EQ(pipe_, fd); | 691 DCHECK_EQ(pipe_, fd); |
663 is_blocked_on_write_ = false; | 692 is_blocked_on_write_ = false; |
664 if (!ProcessOutgoingMessages()) { | 693 if (!ProcessOutgoingMessages()) { |
665 ClosePipeOnError(); | 694 ClosePipeOnError(); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
895 } | 924 } |
896 | 925 |
897 void Channel::ChannelImpl::ClearInputFDs() { | 926 void Channel::ChannelImpl::ClearInputFDs() { |
898 for (size_t i = 0; i < input_fds_.size(); ++i) { | 927 for (size_t i = 0; i < input_fds_.size(); ++i) { |
899 if (HANDLE_EINTR(close(input_fds_[i])) < 0) | 928 if (HANDLE_EINTR(close(input_fds_[i])) < 0) |
900 PLOG(ERROR) << "close "; | 929 PLOG(ERROR) << "close "; |
901 } | 930 } |
902 input_fds_.clear(); | 931 input_fds_.clear(); |
903 } | 932 } |
904 | 933 |
905 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { | 934 void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) { |
935 switch (hops) { | |
936 case 1: | |
937 case 2: { | |
938 // Create the message | |
939 scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE, | |
940 CLOSE_FD_MESSAGE_TYPE, | |
941 IPC::Message::PRIORITY_NORMAL)); | |
942 if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) { | |
943 NOTREACHED() << "Unable to pickle close fd."; | |
944 } | |
945 // Send(msg.release()); | |
946 output_queue_.push(msg.release()); | |
947 break; | |
948 } | |
949 | |
950 default: | |
951 NOTREACHED(); | |
952 break; | |
953 } | |
954 } | |
955 | |
956 void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { | |
906 // The Hello message contains only the process id. | 957 // The Hello message contains only the process id. |
907 PickleIterator iter(msg); | 958 PickleIterator iter(msg); |
908 int pid; | 959 |
909 if (!msg.ReadInt(&iter, &pid)) | 960 switch (msg.type()) { |
910 NOTREACHED(); | 961 default: |
962 NOTREACHED(); | |
963 break; | |
964 | |
965 case Channel::HELLO_MESSAGE_TYPE: | |
966 int pid; | |
967 if (!msg.ReadInt(&iter, &pid)) | |
968 NOTREACHED(); | |
911 | 969 |
912 #if defined(IPC_USES_READWRITE) | 970 #if defined(IPC_USES_READWRITE) |
913 if (mode_ & MODE_SERVER_FLAG) { | 971 if (mode_ & MODE_SERVER_FLAG) { |
914 // With IPC_USES_READWRITE, the Hello message from the client to the | 972 // With IPC_USES_READWRITE, the Hello message from the client to the |
915 // server also contains the fd_pipe_, which will be used for all | 973 // server also contains the fd_pipe_, which will be used for all |
916 // subsequent file descriptor passing. | 974 // subsequent file descriptor passing. |
917 DCHECK_EQ(msg.file_descriptor_set()->size(), 1U); | 975 DCHECK_EQ(msg.file_descriptor_set()->size(), 1U); |
918 base::FileDescriptor descriptor; | 976 base::FileDescriptor descriptor; |
919 if (!msg.ReadFileDescriptor(&iter, &descriptor)) { | 977 if (!msg.ReadFileDescriptor(&iter, &descriptor)) { |
920 NOTREACHED(); | 978 NOTREACHED(); |
921 } | 979 } |
922 fd_pipe_ = descriptor.fd; | 980 fd_pipe_ = descriptor.fd; |
923 CHECK(descriptor.auto_close); | 981 CHECK(descriptor.auto_close); |
982 } | |
983 #endif // IPC_USES_READWRITE | |
984 peer_pid_ = pid; | |
985 listener()->OnChannelConnected(pid); | |
986 break; | |
987 | |
988 #if defined(OS_MACOSX) | |
989 case Channel::CLOSE_FD_MESSAGE_TYPE: | |
990 int fd, hops; | |
991 if (!msg.ReadInt(&iter, &hops)) | |
992 NOTREACHED(); | |
993 if (!msg.ReadInt(&iter, &fd)) | |
994 NOTREACHED(); | |
995 std::set<int>::iterator i = fds_to_close_.find(fd); | |
Scott Hess - ex-Googler
2013/10/09 20:18:33
You only make use of i in one case, which leads to
hubbe
2013/10/09 21:34:12
Yep, much better, done.
| |
996 if (hops == 0) { | |
997 if (i != fds_to_close_.end()) { | |
998 fds_to_close_.erase(i); | |
999 if (HANDLE_EINTR(close(fd)) < 0) | |
1000 PLOG(ERROR) << "close"; | |
1001 } else { | |
1002 NOTREACHED(); | |
1003 } | |
1004 } else { | |
1005 QueueCloseFDMessage(fd, hops); | |
1006 } | |
Scott Hess - ex-Googler
2013/10/09 20:18:33
break;
hubbe
2013/10/09 21:34:12
Done.
| |
1007 #endif | |
924 } | 1008 } |
925 #endif // IPC_USES_READWRITE | |
926 peer_pid_ = pid; | |
927 listener()->OnChannelConnected(pid); | |
928 } | 1009 } |
929 | 1010 |
930 void Channel::ChannelImpl::Close() { | 1011 void Channel::ChannelImpl::Close() { |
931 // Close can be called multiple time, so we need to make sure we're | 1012 // Close can be called multiple time, so we need to make sure we're |
932 // idempotent. | 1013 // idempotent. |
933 | 1014 |
934 ResetToAcceptingConnectionState(); | 1015 ResetToAcceptingConnectionState(); |
935 | 1016 |
936 if (must_unlink_) { | 1017 if (must_unlink_) { |
937 unlink(pipe_name_.c_str()); | 1018 unlink(pipe_name_.c_str()); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1019 | 1100 |
1020 | 1101 |
1021 #if defined(OS_LINUX) | 1102 #if defined(OS_LINUX) |
1022 // static | 1103 // static |
1023 void Channel::SetGlobalPid(int pid) { | 1104 void Channel::SetGlobalPid(int pid) { |
1024 ChannelImpl::SetGlobalPid(pid); | 1105 ChannelImpl::SetGlobalPid(pid); |
1025 } | 1106 } |
1026 #endif // OS_LINUX | 1107 #endif // OS_LINUX |
1027 | 1108 |
1028 } // namespace IPC | 1109 } // namespace IPC |
OLD | NEW |