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

Side by Side Diff: ipc/ipc_channel_posix.cc

Issue 12761003: Revert 187233 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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
« no previous file with comments | « ipc/ipc_channel_posix.h ('k') | ipc/ipc_channel_posix_unittest.cc » ('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 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"
44 43
45 namespace IPC { 44 namespace IPC {
46 45
47 // IPC channels on Windows use named pipes (CreateNamedPipe()) with 46 // IPC channels on Windows use named pipes (CreateNamedPipe()) with
48 // channel ids as the pipe names. Channels on POSIX use sockets as 47 // channel ids as the pipe names. Channels on POSIX use sockets as
49 // pipes These don't quite line up. 48 // pipes These don't quite line up.
50 // 49 //
51 // When creating a child subprocess we use a socket pair and the parent side of 50 // When creating a child subprocess we use a socket pair and the parent side of
52 // the fork arranges it such that the initial control channel ends up on the 51 // the fork arranges it such that the initial control channel ends up on the
53 // magic file descriptor kPrimaryIPCChannel in the child. Future 52 // magic file descriptor kPrimaryIPCChannel in the child. Future
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 130
132 private: 131 private:
133 base::Lock lock_; 132 base::Lock lock_;
134 typedef std::map<std::string, int> ChannelToFDMap; 133 typedef std::map<std::string, int> ChannelToFDMap;
135 ChannelToFDMap map_; 134 ChannelToFDMap map_;
136 135
137 friend struct DefaultSingletonTraits<PipeMap>; 136 friend struct DefaultSingletonTraits<PipeMap>;
138 }; 137 };
139 138
140 //------------------------------------------------------------------------------ 139 //------------------------------------------------------------------------------
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 }
141 277
142 bool SocketWriteErrorIsRecoverable() { 278 bool SocketWriteErrorIsRecoverable() {
143 #if defined(OS_MACOSX) 279 #if defined(OS_MACOSX)
144 // On OS X if sendmsg() is trying to send fds between processes and there 280 // On OS X if sendmsg() is trying to send fds between processes and there
145 // isn't enough room in the output buffer to send the fd structure over 281 // isn't enough room in the output buffer to send the fd structure over
146 // atomically then EMSGSIZE is returned. 282 // atomically then EMSGSIZE is returned.
147 // 283 //
148 // EMSGSIZE presents a problem since the system APIs can only call us when 284 // EMSGSIZE presents a problem since the system APIs can only call us when
149 // there's room in the socket buffer and not when there is "enough" room. 285 // there's room in the socket buffer and not when there is "enough" room.
150 // 286 //
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 return false; 381 return false;
246 } 382 }
247 if (!(value & O_NONBLOCK)) { 383 if (!(value & O_NONBLOCK)) {
248 LOG(ERROR) << "Socket " << pipe_name_ << " must be O_NONBLOCK"; 384 LOG(ERROR) << "Socket " << pipe_name_ << " must be O_NONBLOCK";
249 return false; 385 return false;
250 } 386 }
251 #endif // IPC_USES_READWRITE 387 #endif // IPC_USES_READWRITE
252 } else if (mode_ & MODE_NAMED_FLAG) { 388 } else if (mode_ & MODE_NAMED_FLAG) {
253 // Case 2 from comment above. 389 // Case 2 from comment above.
254 if (mode_ & MODE_SERVER_FLAG) { 390 if (mode_ & MODE_SERVER_FLAG) {
255 if (!CreateServerUnixDomainSocket(base::FilePath(pipe_name_), 391 if (!CreateServerUnixDomainSocket(pipe_name_, &local_pipe)) {
256 &local_pipe)) {
257 return false; 392 return false;
258 } 393 }
259 must_unlink_ = true; 394 must_unlink_ = true;
260 } else if (mode_ & MODE_CLIENT_FLAG) { 395 } else if (mode_ & MODE_CLIENT_FLAG) {
261 if (!CreateClientUnixDomainSocket(base::FilePath(pipe_name_), 396 if (!CreateClientUnixDomainSocket(pipe_name_, &local_pipe)) {
262 &local_pipe)) {
263 return false;
264 }
265 // Verify that the server has the same euid as the client.
266 if (!IPC::IsPeerAuthorized(local_pipe)) {
267 if (HANDLE_EINTR(close(local_pipe)) < 0)
268 PLOG(ERROR) << "close " << pipe_name_;
269 return false; 397 return false;
270 } 398 }
271 } else { 399 } else {
272 LOG(ERROR) << "Bad mode: " << mode_; 400 LOG(ERROR) << "Bad mode: " << mode_;
273 return false; 401 return false;
274 } 402 }
275 } else { 403 } else {
276 local_pipe = PipeMap::GetInstance()->Lookup(pipe_name_); 404 local_pipe = PipeMap::GetInstance()->Lookup(pipe_name_);
277 if (mode_ & MODE_CLIENT_FLAG) { 405 if (mode_ & MODE_CLIENT_FLAG) {
278 if (local_pipe != -1) { 406 if (local_pipe != -1) {
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 } 667 }
540 668
541 bool Channel::ChannelImpl::AcceptsConnections() const { 669 bool Channel::ChannelImpl::AcceptsConnections() const {
542 return server_listen_pipe_ != -1; 670 return server_listen_pipe_ != -1;
543 } 671 }
544 672
545 bool Channel::ChannelImpl::HasAcceptedConnection() const { 673 bool Channel::ChannelImpl::HasAcceptedConnection() const {
546 return AcceptsConnections() && pipe_ != -1; 674 return AcceptsConnections() && pipe_ != -1;
547 } 675 }
548 676
549 bool Channel::ChannelImpl::GetPeerEuid(uid_t* peer_euid) const { 677 bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const {
550 DCHECK(!(mode_ & MODE_SERVER) || HasAcceptedConnection()); 678 DCHECK(HasAcceptedConnection());
551 return IPC::GetPeerEuid(pipe_, peer_euid); 679 #if defined(OS_MACOSX) || defined(OS_OPENBSD)
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
552 } 704 }
553 705
554 void Channel::ChannelImpl::ResetToAcceptingConnectionState() { 706 void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
555 // Unregister libevent for the unix domain socket and close it. 707 // Unregister libevent for the unix domain socket and close it.
556 read_watcher_.StopWatchingFileDescriptor(); 708 read_watcher_.StopWatchingFileDescriptor();
557 write_watcher_.StopWatchingFileDescriptor(); 709 write_watcher_.StopWatchingFileDescriptor();
558 if (pipe_ != -1) { 710 if (pipe_ != -1) {
559 if (HANDLE_EINTR(close(pipe_)) < 0) 711 if (HANDLE_EINTR(close(pipe_)) < 0)
560 PLOG(ERROR) << "close pipe_ " << pipe_name_; 712 PLOG(ERROR) << "close pipe_ " << pipe_name_;
561 pipe_ = -1; 713 pipe_ = -1;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 void Channel::ChannelImpl::SetGlobalPid(int pid) { 746 void Channel::ChannelImpl::SetGlobalPid(int pid) {
595 global_pid_ = pid; 747 global_pid_ = pid;
596 } 748 }
597 #endif // OS_LINUX 749 #endif // OS_LINUX
598 750
599 // Called by libevent when we can read from the pipe without blocking. 751 // Called by libevent when we can read from the pipe without blocking.
600 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { 752 void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
601 bool send_server_hello_msg = false; 753 bool send_server_hello_msg = false;
602 if (fd == server_listen_pipe_) { 754 if (fd == server_listen_pipe_) {
603 int new_pipe = 0; 755 int new_pipe = 0;
604 if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) || 756 if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe)) {
605 new_pipe < 0) {
606 Close(); 757 Close();
607 listener()->OnChannelListenError(); 758 listener()->OnChannelListenError();
608 } 759 }
609 760
610 if (pipe_ != -1) { 761 if (pipe_ != -1) {
611 // We already have a connection. We only handle one at a time. 762 // We already have a connection. We only handle one at a time.
612 // close our new descriptor. 763 // close our new descriptor.
613 if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0) 764 if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0)
614 DPLOG(ERROR) << "shutdown " << pipe_name_; 765 DPLOG(ERROR) << "shutdown " << pipe_name_;
615 if (HANDLE_EINTR(close(new_pipe)) < 0) 766 if (HANDLE_EINTR(close(new_pipe)) < 0)
616 DPLOG(ERROR) << "close " << pipe_name_; 767 DPLOG(ERROR) << "close " << pipe_name_;
617 listener()->OnChannelDenied(); 768 listener()->OnChannelDenied();
618 return; 769 return;
619 } 770 }
620 pipe_ = new_pipe; 771 pipe_ = new_pipe;
621 772
622 if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) { 773 if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) {
623 // Verify that the IPC channel peer is running as the same user. 774 // Verify that the IPC channel peer is running as the same user.
624 uid_t client_euid; 775 uid_t client_euid;
625 if (!GetPeerEuid(&client_euid)) { 776 if (!GetClientEuid(&client_euid)) {
626 DLOG(ERROR) << "Unable to query client euid"; 777 DLOG(ERROR) << "Unable to query client euid";
627 ResetToAcceptingConnectionState(); 778 ResetToAcceptingConnectionState();
628 return; 779 return;
629 } 780 }
630 if (client_euid != geteuid()) { 781 if (client_euid != geteuid()) {
631 DLOG(WARNING) << "Client euid is not authorised"; 782 DLOG(WARNING) << "Client euid is not authorised";
632 ResetToAcceptingConnectionState(); 783 ResetToAcceptingConnectionState();
633 return; 784 return;
634 } 785 }
635 } 786 }
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
999 } 1150 }
1000 1151
1001 bool Channel::AcceptsConnections() const { 1152 bool Channel::AcceptsConnections() const {
1002 return channel_impl_->AcceptsConnections(); 1153 return channel_impl_->AcceptsConnections();
1003 } 1154 }
1004 1155
1005 bool Channel::HasAcceptedConnection() const { 1156 bool Channel::HasAcceptedConnection() const {
1006 return channel_impl_->HasAcceptedConnection(); 1157 return channel_impl_->HasAcceptedConnection();
1007 } 1158 }
1008 1159
1009 bool Channel::GetPeerEuid(uid_t* peer_euid) const { 1160 bool Channel::GetClientEuid(uid_t* client_euid) const {
1010 return channel_impl_->GetPeerEuid(peer_euid); 1161 return channel_impl_->GetClientEuid(client_euid);
1011 } 1162 }
1012 1163
1013 void Channel::ResetToAcceptingConnectionState() { 1164 void Channel::ResetToAcceptingConnectionState() {
1014 channel_impl_->ResetToAcceptingConnectionState(); 1165 channel_impl_->ResetToAcceptingConnectionState();
1015 } 1166 }
1016 1167
1017 // static 1168 // static
1018 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { 1169 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
1019 return ChannelImpl::IsNamedServerInitialized(channel_id); 1170 return ChannelImpl::IsNamedServerInitialized(channel_id);
1020 } 1171 }
(...skipping 12 matching lines...) Expand all
1033 1184
1034 1185
1035 #if defined(OS_LINUX) 1186 #if defined(OS_LINUX)
1036 // static 1187 // static
1037 void Channel::SetGlobalPid(int pid) { 1188 void Channel::SetGlobalPid(int pid) {
1038 ChannelImpl::SetGlobalPid(pid); 1189 ChannelImpl::SetGlobalPid(pid);
1039 } 1190 }
1040 #endif // OS_LINUX 1191 #endif // OS_LINUX
1041 1192
1042 } // namespace IPC 1193 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_posix.h ('k') | ipc/ipc_channel_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698