Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: ipc/ipc_channel_posix.cc

Issue 25325002: workaround for mac kernel bug (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor bugfix Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ipc/ipc_channel_posix.h ('k') | ipc/ipc_channel_reader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 defined(OS_MACOSX)
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 // descriptor. For more information, see:
359 // http://crbug.com/298276
360 std::vector<int> to_close;
361 msg->file_descriptor_set()->ReleaseFDsToClose(&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
350 bool Channel::ChannelImpl::ProcessOutgoingMessages() { 371 bool Channel::ChannelImpl::ProcessOutgoingMessages() {
351 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's 372 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
352 // no connection? 373 // no connection?
353 if (output_queue_.empty()) 374 if (output_queue_.empty())
354 return true; 375 return true;
355 376
356 if (pipe_ == -1) 377 if (pipe_ == -1)
357 return false; 378 return false;
358 379
359 // Write out all the messages we can till the write blocks or there are no 380 // 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
412 // Only the Hello message sends the file descriptor with the message. 433 // Only the Hello message sends the file descriptor with the message.
413 // Subsequently, we can send file descriptors on the dedicated 434 // Subsequently, we can send file descriptors on the dedicated
414 // fd_pipe_ which makes Seccomp sandbox operation more efficient. 435 // fd_pipe_ which makes Seccomp sandbox operation more efficient.
415 struct iovec fd_pipe_iov = { const_cast<char *>(""), 1 }; 436 struct iovec fd_pipe_iov = { const_cast<char *>(""), 1 };
416 msgh.msg_iov = &fd_pipe_iov; 437 msgh.msg_iov = &fd_pipe_iov;
417 fd_written = fd_pipe_; 438 fd_written = fd_pipe_;
418 bytes_written = HANDLE_EINTR(sendmsg(fd_pipe_, &msgh, MSG_DONTWAIT)); 439 bytes_written = HANDLE_EINTR(sendmsg(fd_pipe_, &msgh, MSG_DONTWAIT));
419 msgh.msg_iov = &iov; 440 msgh.msg_iov = &iov;
420 msgh.msg_controllen = 0; 441 msgh.msg_controllen = 0;
421 if (bytes_written > 0) { 442 if (bytes_written > 0) {
422 msg->file_descriptor_set()->CommitAll(); 443 CloseFileDescriptors(msg);
423 } 444 }
424 } 445 }
425 #endif // IPC_USES_READWRITE 446 #endif // IPC_USES_READWRITE
426 } 447 }
427 448
428 if (bytes_written == 1) { 449 if (bytes_written == 1) {
429 fd_written = pipe_; 450 fd_written = pipe_;
430 #if defined(IPC_USES_READWRITE) 451 #if defined(IPC_USES_READWRITE)
431 if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(*msg)) { 452 if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(*msg)) {
432 DCHECK_EQ(msg->file_descriptor_set()->size(), 1U); 453 DCHECK_EQ(msg->file_descriptor_set()->size(), 1U);
433 } 454 }
434 if (!msgh.msg_controllen) { 455 if (!msgh.msg_controllen) {
435 bytes_written = HANDLE_EINTR(write(pipe_, out_bytes, amt_to_write)); 456 bytes_written = HANDLE_EINTR(write(pipe_, out_bytes, amt_to_write));
436 } else 457 } else
437 #endif // IPC_USES_READWRITE 458 #endif // IPC_USES_READWRITE
438 { 459 {
439 bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT)); 460 bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
440 } 461 }
441 } 462 }
442 if (bytes_written > 0) 463 if (bytes_written > 0)
443 msg->file_descriptor_set()->CommitAll(); 464 CloseFileDescriptors(msg);
444 465
445 if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) { 466 if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
446 #if defined(OS_MACOSX) 467 #if defined(OS_MACOSX)
447 // On OSX writing to a pipe with no listener returns EPERM. 468 // On OSX writing to a pipe with no listener returns EPERM.
448 if (errno == EPERM) { 469 if (errno == EPERM) {
449 Close(); 470 Close();
450 return false; 471 return false;
451 } 472 }
452 #endif // OS_MACOSX 473 #endif // OS_MACOSX
453 if (errno == EPIPE) { 474 if (errno == EPIPE) {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 #endif // IPC_USES_READWRITE 589 #endif // IPC_USES_READWRITE
569 590
570 while (!output_queue_.empty()) { 591 while (!output_queue_.empty()) {
571 Message* m = output_queue_.front(); 592 Message* m = output_queue_.front();
572 output_queue_.pop(); 593 output_queue_.pop();
573 delete m; 594 delete m;
574 } 595 }
575 596
576 // Close any outstanding, received file descriptors. 597 // Close any outstanding, received file descriptors.
577 ClearInputFDs(); 598 ClearInputFDs();
599
600 #if defined(OS_MACOSX)
601 // Clear any outstanding, sent file descriptors.
602 for (std::set<int>::iterator i = fds_to_close_.begin();
603 i != fds_to_close_.end();
604 ++i) {
605 if (HANDLE_EINTR(close(*i)) < 0)
606 PLOG(ERROR) << "close";
607 }
608 fds_to_close_.clear();
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
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_) {
656 ProcessOutgoingMessages(); 685 if (!ProcessOutgoingMessages()) {
686 ClosePipeOnError();
687 }
657 } 688 }
658 } 689 }
659 690
660 // Called by libevent when we can write to the pipe without blocking. 691 // Called by libevent when we can write to the pipe without blocking.
661 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) { 692 void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
662 DCHECK_EQ(pipe_, fd); 693 DCHECK_EQ(pipe_, fd);
663 is_blocked_on_write_ = false; 694 is_blocked_on_write_ = false;
664 if (!ProcessOutgoingMessages()) { 695 if (!ProcessOutgoingMessages()) {
665 ClosePipeOnError(); 696 ClosePipeOnError();
666 } 697 }
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 } 926 }
896 927
897 void Channel::ChannelImpl::ClearInputFDs() { 928 void Channel::ChannelImpl::ClearInputFDs() {
898 for (size_t i = 0; i < input_fds_.size(); ++i) { 929 for (size_t i = 0; i < input_fds_.size(); ++i) {
899 if (HANDLE_EINTR(close(input_fds_[i])) < 0) 930 if (HANDLE_EINTR(close(input_fds_[i])) < 0)
900 PLOG(ERROR) << "close "; 931 PLOG(ERROR) << "close ";
901 } 932 }
902 input_fds_.clear(); 933 input_fds_.clear();
903 } 934 }
904 935
905 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { 936 void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) {
937 switch (hops) {
938 case 1:
939 case 2: {
940 // Create the message
941 scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
942 CLOSE_FD_MESSAGE_TYPE,
943 IPC::Message::PRIORITY_NORMAL));
944 if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) {
945 NOTREACHED() << "Unable to pickle close fd.";
946 }
947 // Send(msg.release());
948 output_queue_.push(msg.release());
949 break;
950 }
951
952 default:
953 NOTREACHED();
954 break;
955 }
956 }
957
958 void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) {
906 // The Hello message contains only the process id. 959 // The Hello message contains only the process id.
907 PickleIterator iter(msg); 960 PickleIterator iter(msg);
908 int pid; 961
909 if (!msg.ReadInt(&iter, &pid)) 962 switch (msg.type()) {
910 NOTREACHED(); 963 default:
964 NOTREACHED();
965 break;
966
967 case Channel::HELLO_MESSAGE_TYPE:
968 int pid;
969 if (!msg.ReadInt(&iter, &pid))
970 NOTREACHED();
911 971
912 #if defined(IPC_USES_READWRITE) 972 #if defined(IPC_USES_READWRITE)
913 if (mode_ & MODE_SERVER_FLAG) { 973 if (mode_ & MODE_SERVER_FLAG) {
914 // With IPC_USES_READWRITE, the Hello message from the client to the 974 // 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 975 // server also contains the fd_pipe_, which will be used for all
916 // subsequent file descriptor passing. 976 // subsequent file descriptor passing.
917 DCHECK_EQ(msg.file_descriptor_set()->size(), 1U); 977 DCHECK_EQ(msg.file_descriptor_set()->size(), 1U);
918 base::FileDescriptor descriptor; 978 base::FileDescriptor descriptor;
919 if (!msg.ReadFileDescriptor(&iter, &descriptor)) { 979 if (!msg.ReadFileDescriptor(&iter, &descriptor)) {
920 NOTREACHED(); 980 NOTREACHED();
921 } 981 }
922 fd_pipe_ = descriptor.fd; 982 fd_pipe_ = descriptor.fd;
923 CHECK(descriptor.auto_close); 983 CHECK(descriptor.auto_close);
984 }
985 #endif // IPC_USES_READWRITE
986 peer_pid_ = pid;
987 listener()->OnChannelConnected(pid);
988 break;
989
990 #if defined(OS_MACOSX)
991 case Channel::CLOSE_FD_MESSAGE_TYPE:
992 int fd, hops;
993 if (!msg.ReadInt(&iter, &hops))
994 NOTREACHED();
995 if (!msg.ReadInt(&iter, &fd))
996 NOTREACHED();
997 if (hops == 0) {
998 if (fds_to_close_.erase(fd) > 0) {
999 if (HANDLE_EINTR(close(fd)) < 0)
1000 PLOG(ERROR) << "close";
1001 } else {
1002 NOTREACHED();
1003 }
1004 } else {
1005 QueueCloseFDMessage(fd, hops);
1006 }
1007 break;
1008 #endif
924 } 1009 }
925 #endif // IPC_USES_READWRITE
926 peer_pid_ = pid;
927 listener()->OnChannelConnected(pid);
928 } 1010 }
929 1011
930 void Channel::ChannelImpl::Close() { 1012 void Channel::ChannelImpl::Close() {
931 // Close can be called multiple time, so we need to make sure we're 1013 // Close can be called multiple time, so we need to make sure we're
932 // idempotent. 1014 // idempotent.
933 1015
934 ResetToAcceptingConnectionState(); 1016 ResetToAcceptingConnectionState();
935 1017
936 if (must_unlink_) { 1018 if (must_unlink_) {
937 unlink(pipe_name_.c_str()); 1019 unlink(pipe_name_.c_str());
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1019 1101
1020 1102
1021 #if defined(OS_LINUX) 1103 #if defined(OS_LINUX)
1022 // static 1104 // static
1023 void Channel::SetGlobalPid(int pid) { 1105 void Channel::SetGlobalPid(int pid) {
1024 ChannelImpl::SetGlobalPid(pid); 1106 ChannelImpl::SetGlobalPid(pid);
1025 } 1107 }
1026 #endif // OS_LINUX 1108 #endif // OS_LINUX
1027 1109
1028 } // namespace IPC 1110 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_posix.h ('k') | ipc/ipc_channel_reader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698