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

Side by Side Diff: chrome/browser/process_singleton_posix.cc

Issue 2811173003: ProcessSingletonPosix: don't CHECK if trying to connect to existing process with too long socket sy… (Closed)
Patch Set: updated comments Created 3 years, 8 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
« no previous file with comments | « no previous file | chrome/browser/process_singleton_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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 // On Linux, when the user tries to launch a second copy of chrome, we check 5 // On Linux, when the user tries to launch a second copy of chrome, we check
6 // for a socket in the user's profile directory. If the socket file is open we 6 // for a socket in the user's profile directory. If the socket file is open we
7 // send a message to the first chrome browser process with the current 7 // send a message to the first chrome browser process with the current
8 // directory and second process command line flags. The second process then 8 // directory and second process command line flags. The second process then
9 // exits. 9 // exits.
10 // 10 //
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 return bytes_read; 211 return bytes_read;
212 } else { 212 } else {
213 bytes_read += rv; 213 bytes_read += rv;
214 } 214 }
215 } while (bytes_read < bufsize); 215 } while (bytes_read < bufsize);
216 216
217 return bytes_read; 217 return bytes_read;
218 } 218 }
219 219
220 // Set up a sockaddr appropriate for messaging. 220 // Set up a sockaddr appropriate for messaging.
221 void SetupSockAddr(const std::string& path, struct sockaddr_un* addr) { 221 bool SetupSockAddr(const std::string& path, struct sockaddr_un* addr) {
222 addr->sun_family = AF_UNIX; 222 addr->sun_family = AF_UNIX;
223 CHECK(path.length() < arraysize(addr->sun_path)) 223 if (path.length() >= arraysize(addr->sun_path))
224 << "Socket path too long: " << path; 224 return false;
225 base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path)); 225 base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path));
226 return true;
226 } 227 }
227 228
228 // Set up a socket appropriate for messaging. 229 // Set up a socket appropriate for messaging.
229 int SetupSocketOnly() { 230 int SetupSocketOnly() {
230 int sock = socket(PF_UNIX, SOCK_STREAM, 0); 231 int sock = socket(PF_UNIX, SOCK_STREAM, 0);
231 PCHECK(sock >= 0) << "socket() failed"; 232 PCHECK(sock >= 0) << "socket() failed";
232 233
233 DCHECK(base::SetNonBlocking(sock)) << "Failed to make non-blocking socket."; 234 DCHECK(base::SetNonBlocking(sock)) << "Failed to make non-blocking socket.";
234 int rv = SetCloseOnExec(sock); 235 int rv = SetCloseOnExec(sock);
235 DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket."; 236 DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
236 237
237 return sock; 238 return sock;
238 } 239 }
239 240
240 // Set up a socket and sockaddr appropriate for messaging. 241 // Set up a socket and sockaddr appropriate for messaging.
241 void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) { 242 void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
242 *sock = SetupSocketOnly(); 243 *sock = SetupSocketOnly();
243 SetupSockAddr(path, addr); 244 CHECK(SetupSockAddr(path, addr)) << "Socket path too long: " << path;
244 } 245 }
245 246
246 // Read a symbolic link, return empty string if given path is not a symbol link. 247 // Read a symbolic link, return empty string if given path is not a symbol link.
247 base::FilePath ReadLink(const base::FilePath& path) { 248 base::FilePath ReadLink(const base::FilePath& path) {
248 base::FilePath target; 249 base::FilePath target;
249 if (!base::ReadSymbolicLink(path, &target)) { 250 if (!base::ReadSymbolicLink(path, &target)) {
250 // The only errno that should occur is ENOENT. 251 // The only errno that should occur is ENOENT.
251 if (errno != 0 && errno != ENOENT) 252 if (errno != 0 && errno != ENOENT)
252 PLOG(ERROR) << "readlink(" << path.value() << ") failed"; 253 PLOG(ERROR) << "readlink(" << path.value() << ") failed";
253 } 254 }
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 if (cookie.empty()) 380 if (cookie.empty())
380 return false; 381 return false;
381 base::FilePath remote_cookie = socket_target.DirName(). 382 base::FilePath remote_cookie = socket_target.DirName().
382 Append(chrome::kSingletonCookieFilename); 383 Append(chrome::kSingletonCookieFilename);
383 // Verify the cookie before connecting. 384 // Verify the cookie before connecting.
384 if (!CheckCookie(remote_cookie, cookie)) 385 if (!CheckCookie(remote_cookie, cookie))
385 return false; 386 return false;
386 // Now we know the directory was (at that point) created by the profile 387 // Now we know the directory was (at that point) created by the profile
387 // owner. Try to connect. 388 // owner. Try to connect.
388 sockaddr_un addr; 389 sockaddr_un addr;
389 SetupSockAddr(socket_target.value(), &addr); 390 if (!SetupSockAddr(socket_target.value(), &addr)) {
391 // If a sockaddr couldn't be initialized due to too long of a socket
392 // path, we can be sure there isn't already a Chrome running with this
393 // socket path, since it would have hit the CHECK() on the path length.
394 return false;
395 }
390 int ret = HANDLE_EINTR(connect(socket->fd(), 396 int ret = HANDLE_EINTR(connect(socket->fd(),
391 reinterpret_cast<sockaddr*>(&addr), 397 reinterpret_cast<sockaddr*>(&addr),
392 sizeof(addr))); 398 sizeof(addr)));
393 if (ret != 0) 399 if (ret != 0)
394 return false; 400 return false;
395 // Check the cookie again. We only link in /tmp, which is sticky, so, if the 401 // Check the cookie again. We only link in /tmp, which is sticky, so, if the
396 // directory is still correct, it must have been correct in-between when we 402 // directory is still correct, it must have been correct in-between when we
397 // connected. POSIX, sadly, lacks a connectat(). 403 // connected. POSIX, sadly, lacks a connectat().
398 if (!CheckCookie(remote_cookie, cookie)) { 404 if (!CheckCookie(remote_cookie, cookie)) {
399 socket->Reset(); 405 socket->Reset();
400 return false; 406 return false;
401 } 407 }
402 // Success! 408 // Success!
403 return true; 409 return true;
404 } else if (errno == EINVAL) { 410 } else if (errno == EINVAL) {
405 // It exists, but is not a symlink (or some other error we detect 411 // It exists, but is not a symlink (or some other error we detect
406 // later). Just connect to it directly; this is an older version of Chrome. 412 // later). Just connect to it directly; this is an older version of Chrome.
407 sockaddr_un addr; 413 sockaddr_un addr;
408 SetupSockAddr(socket_path.value(), &addr); 414 if (!SetupSockAddr(socket_path.value(), &addr)) {
415 // If a sockaddr couldn't be initialized due to too long of a socket
416 // path, we can be sure there isn't already a Chrome running with this
417 // socket path, since it would have hit the CHECK() on the path length.
418 return false;
419 }
409 int ret = HANDLE_EINTR(connect(socket->fd(), 420 int ret = HANDLE_EINTR(connect(socket->fd(),
410 reinterpret_cast<sockaddr*>(&addr), 421 reinterpret_cast<sockaddr*>(&addr),
411 sizeof(addr))); 422 sizeof(addr)));
412 return (ret == 0); 423 return (ret == 0);
413 } else { 424 } else {
414 // File is missing, or other error. 425 // File is missing, or other error.
415 if (errno != ENOENT) 426 if (errno != ENOENT)
416 PLOG(ERROR) << "readlink failed"; 427 PLOG(ERROR) << "readlink failed";
417 return false; 428 return false;
418 } 429 }
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after
975 LOG(ERROR) << "Failed to create socket directory."; 986 LOG(ERROR) << "Failed to create socket directory.";
976 return false; 987 return false;
977 } 988 }
978 989
979 // Check that the directory was created with the correct permissions. 990 // Check that the directory was created with the correct permissions.
980 int dir_mode = 0; 991 int dir_mode = 0;
981 CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) && 992 CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) &&
982 dir_mode == base::FILE_PERMISSION_USER_MASK) 993 dir_mode == base::FILE_PERMISSION_USER_MASK)
983 << "Temp directory mode is not 700: " << std::oct << dir_mode; 994 << "Temp directory mode is not 700: " << std::oct << dir_mode;
984 995
985 // Setup the socket symlink and the two cookies. 996 // Try to create the socket before creating the symlink, as SetupSocket may
997 // fail on a CHECK if the |socket_target_path| is too long, and this avoids
998 // leaving a dangling symlink.
986 base::FilePath socket_target_path = 999 base::FilePath socket_target_path =
987 socket_dir_.GetPath().Append(chrome::kSingletonSocketFilename); 1000 socket_dir_.GetPath().Append(chrome::kSingletonSocketFilename);
1001 SetupSocket(socket_target_path.value(), &sock, &addr);
1002
1003 // Setup the socket symlink and the two cookies.
988 base::FilePath cookie(GenerateCookie()); 1004 base::FilePath cookie(GenerateCookie());
989 base::FilePath remote_cookie_path = 1005 base::FilePath remote_cookie_path =
990 socket_dir_.GetPath().Append(chrome::kSingletonCookieFilename); 1006 socket_dir_.GetPath().Append(chrome::kSingletonCookieFilename);
991 UnlinkPath(socket_path_); 1007 UnlinkPath(socket_path_);
992 UnlinkPath(cookie_path_); 1008 UnlinkPath(cookie_path_);
993 if (!SymlinkPath(socket_target_path, socket_path_) || 1009 if (!SymlinkPath(socket_target_path, socket_path_) ||
994 !SymlinkPath(cookie, cookie_path_) || 1010 !SymlinkPath(cookie, cookie_path_) ||
995 !SymlinkPath(cookie, remote_cookie_path)) { 1011 !SymlinkPath(cookie, remote_cookie_path)) {
996 // We've already locked things, so we can't have lost the startup race, 1012 // We've already locked things, so we can't have lost the startup race,
997 // but something doesn't like us. 1013 // but something doesn't like us.
998 LOG(ERROR) << "Failed to create symlinks."; 1014 LOG(ERROR) << "Failed to create symlinks.";
999 if (!socket_dir_.Delete()) 1015 if (!socket_dir_.Delete())
1000 LOG(ERROR) << "Encountered a problem when deleting socket directory."; 1016 LOG(ERROR) << "Encountered a problem when deleting socket directory.";
1001 return false; 1017 return false;
1002 } 1018 }
1003 1019
1004 SetupSocket(socket_target_path.value(), &sock, &addr);
1005
1006 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { 1020 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
1007 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value(); 1021 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
1008 CloseSocket(sock); 1022 CloseSocket(sock);
1009 return false; 1023 return false;
1010 } 1024 }
1011 1025
1012 if (listen(sock, 5) < 0) 1026 if (listen(sock, 5) < 0)
1013 NOTREACHED() << "listen failed: " << base::safe_strerror(errno); 1027 NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
1014 1028
1015 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO)); 1029 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 } 1078 }
1065 1079
1066 void ProcessSingleton::KillProcess(int pid) { 1080 void ProcessSingleton::KillProcess(int pid) {
1067 // TODO(james.su@gmail.com): Is SIGKILL ok? 1081 // TODO(james.su@gmail.com): Is SIGKILL ok?
1068 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 1082 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
1069 // ESRCH = No Such Process (can happen if the other process is already in 1083 // ESRCH = No Such Process (can happen if the other process is already in
1070 // progress of shutting down and finishes before we try to kill it). 1084 // progress of shutting down and finishes before we try to kill it).
1071 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 1085 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
1072 << base::safe_strerror(errno); 1086 << base::safe_strerror(errno);
1073 } 1087 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/process_singleton_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698