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 |