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

Side by Side Diff: ipc/ipc_channel_posix.cc

Issue 12386010: Implement IPC::ChannelFactory, a class that accept()s on a UNIX socket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 7 years, 9 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
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 22 matching lines...) Expand all
33 #include "base/rand_util.h" 33 #include "base/rand_util.h"
34 #include "base/stl_util.h" 34 #include "base/stl_util.h"
35 #include "base/string_util.h" 35 #include "base/string_util.h"
36 #include "base/synchronization/lock.h" 36 #include "base/synchronization/lock.h"
37 #include "ipc/file_descriptor_set_posix.h" 37 #include "ipc/file_descriptor_set_posix.h"
38 #include "ipc/ipc_descriptors.h" 38 #include "ipc/ipc_descriptors.h"
39 #include "ipc/ipc_listener.h" 39 #include "ipc/ipc_listener.h"
40 #include "ipc/ipc_logging.h" 40 #include "ipc/ipc_logging.h"
41 #include "ipc/ipc_message_utils.h" 41 #include "ipc/ipc_message_utils.h"
42 #include "ipc/ipc_switches.h" 42 #include "ipc/ipc_switches.h"
43 #include "ipc/unix_domain_socket_util.h"
43 44
44 namespace IPC { 45 namespace IPC {
45 46
46 // IPC channels on Windows use named pipes (CreateNamedPipe()) with 47 // IPC channels on Windows use named pipes (CreateNamedPipe()) with
47 // channel ids as the pipe names. Channels on POSIX use sockets as 48 // channel ids as the pipe names. Channels on POSIX use sockets as
48 // pipes These don't quite line up. 49 // pipes These don't quite line up.
49 // 50 //
50 // When creating a child subprocess we use a socket pair and the parent side of 51 // When creating a child subprocess we use a socket pair and the parent side of
51 // the fork arranges it such that the initial control channel ends up on the 52 // the fork arranges it such that the initial control channel ends up on the
52 // magic file descriptor kPrimaryIPCChannel in the child. Future 53 // magic file descriptor kPrimaryIPCChannel in the child. Future
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 131
131 private: 132 private:
132 base::Lock lock_; 133 base::Lock lock_;
133 typedef std::map<std::string, int> ChannelToFDMap; 134 typedef std::map<std::string, int> ChannelToFDMap;
134 ChannelToFDMap map_; 135 ChannelToFDMap map_;
135 136
136 friend struct DefaultSingletonTraits<PipeMap>; 137 friend struct DefaultSingletonTraits<PipeMap>;
137 }; 138 };
138 139
139 //------------------------------------------------------------------------------ 140 //------------------------------------------------------------------------------
140 // Verify that kMaxPipeNameLength is a decent size.
141 COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxPipeNameLength,
142 BAD_SUN_PATH_LENGTH);
143
144 // Creates a unix domain socket bound to the specified name that is listening
145 // for connections.
146 bool CreateServerUnixDomainSocket(const std::string& pipe_name,
147 int* server_listen_fd) {
148 DCHECK(server_listen_fd);
149
150 if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
151 DLOG(ERROR) << "pipe_name.length() == " << pipe_name.length();
152 return false;
153 }
154
155 // Create socket.
156 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
157 if (fd < 0) {
158 return false;
159 }
160
161 // Make socket non-blocking
162 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
163 PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
164 if (HANDLE_EINTR(close(fd)) < 0)
165 PLOG(ERROR) << "close " << pipe_name;
166 return false;
167 }
168
169 // Delete any old FS instances.
170 unlink(pipe_name.c_str());
171
172 // Make sure the path we need exists.
173 base::FilePath path(pipe_name);
174 base::FilePath dir_path = path.DirName();
175 if (!file_util::CreateDirectory(dir_path)) {
176 if (HANDLE_EINTR(close(fd)) < 0)
177 PLOG(ERROR) << "close " << pipe_name;
178 return false;
179 }
180
181 // Create unix_addr structure.
182 struct sockaddr_un unix_addr;
183 memset(&unix_addr, 0, sizeof(unix_addr));
184 unix_addr.sun_family = AF_UNIX;
185 int path_len = snprintf(unix_addr.sun_path, IPC::kMaxPipeNameLength,
186 "%s", pipe_name.c_str());
187 DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
188 size_t unix_addr_len = offsetof(struct sockaddr_un,
189 sun_path) + path_len + 1;
190
191 // Bind the socket.
192 if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
193 unix_addr_len) != 0) {
194 PLOG(ERROR) << "bind " << pipe_name;
195 if (HANDLE_EINTR(close(fd)) < 0)
196 PLOG(ERROR) << "close " << pipe_name;
197 return false;
198 }
199
200 // Start listening on the socket.
201 const int listen_queue_length = 1;
202 if (listen(fd, listen_queue_length) != 0) {
203 PLOG(ERROR) << "listen " << pipe_name;
204 if (HANDLE_EINTR(close(fd)) < 0)
205 PLOG(ERROR) << "close " << pipe_name;
206 return false;
207 }
208
209 *server_listen_fd = fd;
210 return true;
211 }
212
213 // Accept a connection on a socket we are listening to.
214 bool ServerAcceptConnection(int server_listen_fd, int* server_socket) {
215 DCHECK(server_socket);
216
217 int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
218 if (accept_fd < 0)
219 return false;
220 if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
221 PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd;
222 if (HANDLE_EINTR(close(accept_fd)) < 0)
223 PLOG(ERROR) << "close " << accept_fd;
224 return false;
225 }
226
227 *server_socket = accept_fd;
228 return true;
229 }
230
231 bool CreateClientUnixDomainSocket(const std::string& pipe_name,
232 int* client_socket) {
233 DCHECK(client_socket);
234 DCHECK_GT(pipe_name.length(), 0u);
235 DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
236
237 if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
238 return false;
239 }
240
241 // Create socket.
242 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
243 if (fd < 0) {
244 PLOG(ERROR) << "socket " << pipe_name;
245 return false;
246 }
247
248 // Make socket non-blocking
249 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
250 PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
251 if (HANDLE_EINTR(close(fd)) < 0)
252 PLOG(ERROR) << "close " << pipe_name;
253 return false;
254 }
255
256 // Create server side of socket.
257 struct sockaddr_un server_unix_addr;
258 memset(&server_unix_addr, 0, sizeof(server_unix_addr));
259 server_unix_addr.sun_family = AF_UNIX;
260 int path_len = snprintf(server_unix_addr.sun_path, IPC::kMaxPipeNameLength,
261 "%s", pipe_name.c_str());
262 DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
263 size_t server_unix_addr_len = offsetof(struct sockaddr_un,
264 sun_path) + path_len + 1;
265
266 if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
267 server_unix_addr_len)) != 0) {
268 PLOG(ERROR) << "connect " << pipe_name;
269 if (HANDLE_EINTR(close(fd)) < 0)
270 PLOG(ERROR) << "close " << pipe_name;
271 return false;
272 }
273
274 *client_socket = fd;
275 return true;
276 }
277 141
278 bool SocketWriteErrorIsRecoverable() { 142 bool SocketWriteErrorIsRecoverable() {
279 #if defined(OS_MACOSX) 143 #if defined(OS_MACOSX)
280 // On OS X if sendmsg() is trying to send fds between processes and there 144 // On OS X if sendmsg() is trying to send fds between processes and there
281 // isn't enough room in the output buffer to send the fd structure over 145 // isn't enough room in the output buffer to send the fd structure over
282 // atomically then EMSGSIZE is returned. 146 // atomically then EMSGSIZE is returned.
283 // 147 //
284 // EMSGSIZE presents a problem since the system APIs can only call us when 148 // EMSGSIZE presents a problem since the system APIs can only call us when
285 // there's room in the socket buffer and not when there is "enough" room. 149 // there's room in the socket buffer and not when there is "enough" room.
286 // 150 //
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 return false; 245 return false;
382 } 246 }
383 if (!(value & O_NONBLOCK)) { 247 if (!(value & O_NONBLOCK)) {
384 LOG(ERROR) << "Socket " << pipe_name_ << " must be O_NONBLOCK"; 248 LOG(ERROR) << "Socket " << pipe_name_ << " must be O_NONBLOCK";
385 return false; 249 return false;
386 } 250 }
387 #endif // IPC_USES_READWRITE 251 #endif // IPC_USES_READWRITE
388 } else if (mode_ & MODE_NAMED_FLAG) { 252 } else if (mode_ & MODE_NAMED_FLAG) {
389 // Case 2 from comment above. 253 // Case 2 from comment above.
390 if (mode_ & MODE_SERVER_FLAG) { 254 if (mode_ & MODE_SERVER_FLAG) {
391 if (!CreateServerUnixDomainSocket(pipe_name_, &local_pipe)) { 255 if (!CreateServerUnixDomainSocket(base::FilePath(pipe_name_),
256 &local_pipe)) {
392 return false; 257 return false;
393 } 258 }
394 must_unlink_ = true; 259 must_unlink_ = true;
395 } else if (mode_ & MODE_CLIENT_FLAG) { 260 } else if (mode_ & MODE_CLIENT_FLAG) {
396 if (!CreateClientUnixDomainSocket(pipe_name_, &local_pipe)) { 261 if (!CreateClientUnixDomainSocket(base::FilePath(pipe_name_),
262 &local_pipe)) {
263 return false;
264 }
265 // Verify that the server has the same euid as the client.
266 uid_t server_euid;
267 if (!IPC::GetPeerEuid(local_pipe, &server_euid)) {
Mark Mentovai 2013/03/05 20:08:03 You have identical logic in ipc_channel_factory.cc
jeremya 2013/03/06 05:03:18 Done.
268 DLOG(ERROR) << "Unable to query server euid";
269 HANDLE_EINTR(close(local_pipe));
270 return false;
271 }
272 if (server_euid != geteuid()) {
273 DLOG(ERROR) << "Server euid is not authorised";
274 HANDLE_EINTR(close(local_pipe));
397 return false; 275 return false;
398 } 276 }
399 } else { 277 } else {
400 LOG(ERROR) << "Bad mode: " << mode_; 278 LOG(ERROR) << "Bad mode: " << mode_;
401 return false; 279 return false;
402 } 280 }
403 } else { 281 } else {
404 local_pipe = PipeMap::GetInstance()->Lookup(pipe_name_); 282 local_pipe = PipeMap::GetInstance()->Lookup(pipe_name_);
405 if (mode_ & MODE_CLIENT_FLAG) { 283 if (mode_ & MODE_CLIENT_FLAG) {
406 if (local_pipe != -1) { 284 if (local_pipe != -1) {
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 } 545 }
668 546
669 bool Channel::ChannelImpl::AcceptsConnections() const { 547 bool Channel::ChannelImpl::AcceptsConnections() const {
670 return server_listen_pipe_ != -1; 548 return server_listen_pipe_ != -1;
671 } 549 }
672 550
673 bool Channel::ChannelImpl::HasAcceptedConnection() const { 551 bool Channel::ChannelImpl::HasAcceptedConnection() const {
674 return AcceptsConnections() && pipe_ != -1; 552 return AcceptsConnections() && pipe_ != -1;
675 } 553 }
676 554
677 bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const { 555 bool Channel::ChannelImpl::GetPeerEuid(uid_t* peer_euid) const {
678 DCHECK(HasAcceptedConnection()); 556 DCHECK(!(mode_ & MODE_SERVER) || HasAcceptedConnection());
679 #if defined(OS_MACOSX) || defined(OS_OPENBSD) 557 return IPC::GetPeerEuid(pipe_, peer_euid);
680 uid_t peer_euid;
681 gid_t peer_gid;
682 if (getpeereid(pipe_, &peer_euid, &peer_gid) != 0) {
683 PLOG(ERROR) << "getpeereid " << pipe_;
684 return false;
685 }
686 *client_euid = peer_euid;
687 return true;
688 #elif defined(OS_SOLARIS)
689 return false;
690 #else
691 struct ucred cred;
692 socklen_t cred_len = sizeof(cred);
693 if (getsockopt(pipe_, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != 0) {
694 PLOG(ERROR) << "getsockopt " << pipe_;
695 return false;
696 }
697 if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
698 NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
699 return false;
700 }
701 *client_euid = cred.uid;
702 return true;
703 #endif
704 } 558 }
705 559
706 void Channel::ChannelImpl::ResetToAcceptingConnectionState() { 560 void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
707 // Unregister libevent for the unix domain socket and close it. 561 // Unregister libevent for the unix domain socket and close it.
708 read_watcher_.StopWatchingFileDescriptor(); 562 read_watcher_.StopWatchingFileDescriptor();
709 write_watcher_.StopWatchingFileDescriptor(); 563 write_watcher_.StopWatchingFileDescriptor();
710 if (pipe_ != -1) { 564 if (pipe_ != -1) {
711 if (HANDLE_EINTR(close(pipe_)) < 0) 565 if (HANDLE_EINTR(close(pipe_)) < 0)
712 PLOG(ERROR) << "close pipe_ " << pipe_name_; 566 PLOG(ERROR) << "close pipe_ " << pipe_name_;
713 pipe_ = -1; 567 pipe_ = -1;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 if (HANDLE_EINTR(close(new_pipe)) < 0) 620 if (HANDLE_EINTR(close(new_pipe)) < 0)
767 DPLOG(ERROR) << "close " << pipe_name_; 621 DPLOG(ERROR) << "close " << pipe_name_;
768 listener()->OnChannelDenied(); 622 listener()->OnChannelDenied();
769 return; 623 return;
770 } 624 }
771 pipe_ = new_pipe; 625 pipe_ = new_pipe;
772 626
773 if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) { 627 if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) {
774 // Verify that the IPC channel peer is running as the same user. 628 // Verify that the IPC channel peer is running as the same user.
775 uid_t client_euid; 629 uid_t client_euid;
776 if (!GetClientEuid(&client_euid)) { 630 if (!GetPeerEuid(&client_euid)) {
777 DLOG(ERROR) << "Unable to query client euid"; 631 DLOG(ERROR) << "Unable to query client euid";
778 ResetToAcceptingConnectionState(); 632 ResetToAcceptingConnectionState();
779 return; 633 return;
780 } 634 }
781 if (client_euid != geteuid()) { 635 if (client_euid != geteuid()) {
782 DLOG(WARNING) << "Client euid is not authorised"; 636 DLOG(WARNING) << "Client euid is not authorised";
783 ResetToAcceptingConnectionState(); 637 ResetToAcceptingConnectionState();
784 return; 638 return;
785 } 639 }
786 } 640 }
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 } 1004 }
1151 1005
1152 bool Channel::AcceptsConnections() const { 1006 bool Channel::AcceptsConnections() const {
1153 return channel_impl_->AcceptsConnections(); 1007 return channel_impl_->AcceptsConnections();
1154 } 1008 }
1155 1009
1156 bool Channel::HasAcceptedConnection() const { 1010 bool Channel::HasAcceptedConnection() const {
1157 return channel_impl_->HasAcceptedConnection(); 1011 return channel_impl_->HasAcceptedConnection();
1158 } 1012 }
1159 1013
1160 bool Channel::GetClientEuid(uid_t* client_euid) const { 1014 bool Channel::GetPeerEuid(uid_t* peer_euid) const {
1161 return channel_impl_->GetClientEuid(client_euid); 1015 return channel_impl_->GetPeerEuid(peer_euid);
1162 } 1016 }
1163 1017
1164 void Channel::ResetToAcceptingConnectionState() { 1018 void Channel::ResetToAcceptingConnectionState() {
1165 channel_impl_->ResetToAcceptingConnectionState(); 1019 channel_impl_->ResetToAcceptingConnectionState();
1166 } 1020 }
1167 1021
1168 // static 1022 // static
1169 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { 1023 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
1170 return ChannelImpl::IsNamedServerInitialized(channel_id); 1024 return ChannelImpl::IsNamedServerInitialized(channel_id);
1171 } 1025 }
(...skipping 12 matching lines...) Expand all
1184 1038
1185 1039
1186 #if defined(OS_LINUX) 1040 #if defined(OS_LINUX)
1187 // static 1041 // static
1188 void Channel::SetGlobalPid(int pid) { 1042 void Channel::SetGlobalPid(int pid) {
1189 ChannelImpl::SetGlobalPid(pid); 1043 ChannelImpl::SetGlobalPid(pid);
1190 } 1044 }
1191 #endif // OS_LINUX 1045 #endif // OS_LINUX
1192 1046
1193 } // namespace IPC 1047 } // namespace IPC
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698