| OLD | NEW |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #include "util/mach/child_port_handshake.h" | 15 #include "util/mach/child_port_handshake.h" |
| 16 | 16 |
| 17 #include <errno.h> | 17 #include <errno.h> |
| 18 #include <fcntl.h> | |
| 19 #include <pthread.h> | 18 #include <pthread.h> |
| 20 #include <servers/bootstrap.h> | 19 #include <servers/bootstrap.h> |
| 21 #include <sys/event.h> | 20 #include <sys/event.h> |
| 21 #include <sys/socket.h> |
| 22 #include <sys/time.h> | 22 #include <sys/time.h> |
| 23 #include <sys/types.h> | 23 #include <sys/types.h> |
| 24 #include <unistd.h> | 24 #include <unistd.h> |
| 25 | 25 |
| 26 #include <algorithm> | 26 #include <algorithm> |
| 27 | 27 |
| 28 #include "base/logging.h" | 28 #include "base/logging.h" |
| 29 #include "base/mac/mach_logging.h" | 29 #include "base/mac/mach_logging.h" |
| 30 #include "base/mac/scoped_mach_port.h" | 30 #include "base/mac/scoped_mach_port.h" |
| 31 #include "base/posix/eintr_wrapper.h" | 31 #include "base/posix/eintr_wrapper.h" |
| 32 #include "base/rand_util.h" | 32 #include "base/rand_util.h" |
| 33 #include "base/strings/stringprintf.h" | 33 #include "base/strings/stringprintf.h" |
| 34 #include "util/file/fd_io.h" | 34 #include "util/file/fd_io.h" |
| 35 #include "util/mach/child_port.h" | 35 #include "util/mach/child_port.h" |
| 36 #include "util/mach/mach_extensions.h" | 36 #include "util/mach/mach_extensions.h" |
| 37 #include "util/mach/mach_message_server.h" | 37 #include "util/mach/mach_message_server.h" |
| 38 | 38 |
| 39 namespace crashpad { | 39 namespace crashpad { |
| 40 | 40 |
| 41 ChildPortHandshake::ChildPortHandshake() | 41 ChildPortHandshake::ChildPortHandshake() |
| 42 : token_(0), | 42 : token_(0), |
| 43 pipe_read_(), | 43 pipe_read_(), |
| 44 pipe_write_(), | 44 pipe_write_(), |
| 45 child_port_(MACH_PORT_NULL), | 45 child_port_(MACH_PORT_NULL), |
| 46 checked_in_(false) { | 46 checked_in_(false) { |
| 47 // Use socketpair() instead of pipe(). There is no way to suppress SIGPIPE on |
| 48 // pipes in Mac OS X 10.6, because the F_SETNOSIGPIPE fcntl() command was not |
| 49 // introduced until 10.7. |
| 47 int pipe_fds[2]; | 50 int pipe_fds[2]; |
| 48 int rv = pipe(pipe_fds); | 51 PCHECK(socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fds) == 0) |
| 49 PCHECK(rv == 0) << "pipe"; | 52 << "socketpair"; |
| 50 | 53 |
| 51 pipe_read_.reset(pipe_fds[0]); | 54 pipe_read_.reset(pipe_fds[0]); |
| 52 pipe_write_.reset(pipe_fds[1]); | 55 pipe_write_.reset(pipe_fds[1]); |
| 53 | 56 |
| 57 // Simulate pipe() semantics by shutting down the “wrong” sides of the socket. |
| 58 PCHECK(shutdown(pipe_write_.get(), SHUT_RD) == 0) << "shutdown"; |
| 59 PCHECK(shutdown(pipe_read_.get(), SHUT_WR) == 0) << "shutdown"; |
| 60 |
| 54 // SIGPIPE is undesirable when writing to this pipe. Allow broken-pipe writes | 61 // SIGPIPE is undesirable when writing to this pipe. Allow broken-pipe writes |
| 55 // to fail with EPIPE instead. | 62 // to fail with EPIPE instead. |
| 56 PCHECK(fcntl(pipe_write_.get(), F_SETNOSIGPIPE, 1) == 0) << "fcntl"; | 63 const int value = 1; |
| 64 PCHECK(setsockopt( |
| 65 pipe_write_.get(), SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) == 0) |
| 66 << "setsockopt"; |
| 57 } | 67 } |
| 58 | 68 |
| 59 ChildPortHandshake::~ChildPortHandshake() { | 69 ChildPortHandshake::~ChildPortHandshake() { |
| 60 } | 70 } |
| 61 | 71 |
| 62 int ChildPortHandshake::ReadPipeFD() const { | 72 int ChildPortHandshake::ReadPipeFD() const { |
| 63 DCHECK_NE(pipe_read_.get(), -1); | 73 DCHECK_NE(pipe_read_.get(), -1); |
| 64 return pipe_read_.get(); | 74 return pipe_read_.get(); |
| 65 } | 75 } |
| 66 | 76 |
| 67 mach_port_t ChildPortHandshake::RunServer() { | 77 mach_port_t ChildPortHandshake::RunServer() { |
| 68 DCHECK_NE(pipe_read_.get(), -1); | 78 DCHECK_NE(pipe_read_.get(), -1); |
| 69 pipe_read_.reset(); | 79 pipe_read_.reset(); |
| 70 | 80 |
| 71 // Transfer ownership of the write pipe into this method’s scope. | 81 // Transfer ownership of the write pipe into this method’s scope. |
| 72 base::ScopedFD pipe_write_owner(pipe_write_.release()); | 82 base::ScopedFD pipe_write_owner(pipe_write_.release()); |
| 73 | 83 |
| 74 // Initialize the token and share it with the client via the pipe. | 84 // Initialize the token and share it with the client via the pipe. |
| 75 token_ = base::RandUint64(); | 85 token_ = base::RandUint64(); |
| 76 int pipe_write = pipe_write_owner.get(); | 86 int pipe_write = pipe_write_owner.get(); |
| 77 if (!LoggingWriteFD(pipe_write, &token_, sizeof(token_))) { | 87 if (!LoggingWriteFD(pipe_write, &token_, sizeof(token_))) { |
| 88 LOG(WARNING) << "no client check-in"; |
| 78 return MACH_PORT_NULL; | 89 return MACH_PORT_NULL; |
| 79 } | 90 } |
| 80 | 91 |
| 81 // Create a unique name for the bootstrap service mapping. Make it unguessable | 92 // Create a unique name for the bootstrap service mapping. Make it unguessable |
| 82 // to prevent outsiders from grabbing the name first, which would cause | 93 // to prevent outsiders from grabbing the name first, which would cause |
| 83 // bootstrap_check_in() to fail. | 94 // bootstrap_check_in() to fail. |
| 84 uint64_t thread_id; | 95 uint64_t thread_id; |
| 85 errno = pthread_threadid_np(pthread_self(), &thread_id); | 96 errno = pthread_threadid_np(pthread_self(), &thread_id); |
| 86 PCHECK(errno == 0) << "pthread_threadid_np"; | 97 PCHECK(errno == 0) << "pthread_threadid_np"; |
| 87 std::string service_name = base::StringPrintf( | 98 std::string service_name = base::StringPrintf( |
| 88 "com.googlecode.crashpad.child_port_handshake.%d.%llu.%016llx", | 99 "com.googlecode.crashpad.child_port_handshake.%d.%llu.%016llx", |
| 89 getpid(), | 100 getpid(), |
| 90 thread_id, | 101 thread_id, |
| 91 base::RandUint64()); | 102 base::RandUint64()); |
| 92 DCHECK_LT(service_name.size(), implicit_cast<size_t>(BOOTSTRAP_MAX_NAME_LEN)); | 103 DCHECK_LT(service_name.size(), implicit_cast<size_t>(BOOTSTRAP_MAX_NAME_LEN)); |
| 93 | 104 |
| 94 // Check the new service in with the bootstrap server, obtaining a receive | 105 // Check the new service in with the bootstrap server, obtaining a receive |
| 95 // right for it. | 106 // right for it. |
| 96 mach_port_t server_port; | 107 mach_port_t server_port; |
| 97 kern_return_t kr = | 108 kern_return_t kr = |
| 98 bootstrap_check_in(bootstrap_port, service_name.c_str(), &server_port); | 109 bootstrap_check_in(bootstrap_port, service_name.c_str(), &server_port); |
| 99 BOOTSTRAP_CHECK(kr == BOOTSTRAP_SUCCESS, kr) << "bootstrap_check_in"; | 110 BOOTSTRAP_CHECK(kr == BOOTSTRAP_SUCCESS, kr) << "bootstrap_check_in"; |
| 100 base::mac::ScopedMachReceiveRight server_port_owner(server_port); | 111 base::mac::ScopedMachReceiveRight server_port_owner(server_port); |
| 101 | 112 |
| 102 // Share the service name with the client via the pipe. | 113 // Share the service name with the client via the pipe. |
| 103 uint32_t service_name_length = service_name.size(); | 114 uint32_t service_name_length = service_name.size(); |
| 104 if (!LoggingWriteFD( | 115 if (!LoggingWriteFD( |
| 105 pipe_write, &service_name_length, sizeof(service_name_length))) { | 116 pipe_write, &service_name_length, sizeof(service_name_length))) { |
| 117 LOG(WARNING) << "no client check-in"; |
| 106 return MACH_PORT_NULL; | 118 return MACH_PORT_NULL; |
| 107 } | 119 } |
| 108 | 120 |
| 109 if (!LoggingWriteFD(pipe_write, service_name.c_str(), service_name_length)) { | 121 if (!LoggingWriteFD(pipe_write, service_name.c_str(), service_name_length)) { |
| 122 LOG(WARNING) << "no client check-in"; |
| 110 return MACH_PORT_NULL; | 123 return MACH_PORT_NULL; |
| 111 } | 124 } |
| 112 | 125 |
| 113 // A kqueue cannot monitor a raw Mach receive right with EVFILT_MACHPORT. It | 126 // A kqueue cannot monitor a raw Mach receive right with EVFILT_MACHPORT. It |
| 114 // requires a port set. Create a new port set and add the receive right to it. | 127 // requires a port set. Create a new port set and add the receive right to it. |
| 115 mach_port_t server_port_set; | 128 mach_port_t server_port_set; |
| 116 kr = mach_port_allocate( | 129 kr = mach_port_allocate( |
| 117 mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &server_port_set); | 130 mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &server_port_set); |
| 118 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_allocate"; | 131 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_allocate"; |
| 119 base::mac::ScopedMachPortSet server_port_set_owner(server_port_set); | 132 base::mac::ScopedMachPortSet server_port_set_owner(server_port_set); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 bootstrap_look_up(bootstrap_port, service_name.c_str(), &server_port); | 340 bootstrap_look_up(bootstrap_port, service_name.c_str(), &server_port); |
| 328 BOOTSTRAP_CHECK(kr == BOOTSTRAP_SUCCESS, kr) << "bootstrap_look_up"; | 341 BOOTSTRAP_CHECK(kr == BOOTSTRAP_SUCCESS, kr) << "bootstrap_look_up"; |
| 329 base::mac::ScopedMachSendRight server_port_owner(server_port); | 342 base::mac::ScopedMachSendRight server_port_owner(server_port); |
| 330 | 343 |
| 331 // Check in with the server. | 344 // Check in with the server. |
| 332 kr = child_port_check_in(server_port, token, port, right_type); | 345 kr = child_port_check_in(server_port, token, port, right_type); |
| 333 MACH_CHECK(kr == KERN_SUCCESS, kr) << "child_port_check_in"; | 346 MACH_CHECK(kr == KERN_SUCCESS, kr) << "child_port_check_in"; |
| 334 } | 347 } |
| 335 | 348 |
| 336 } // namespace crashpad | 349 } // namespace crashpad |
| OLD | NEW |