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

Side by Side Diff: chrome/browser/renderer_host/render_crash_handler_host_linux.cc

Issue 149230: Linux: SUID sandbox support (Closed)
Patch Set: ... Created 11 years, 5 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
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "chrome/browser/renderer_host/render_crash_handler_host_linux.h" 5 #include "chrome/browser/renderer_host/render_crash_handler_host_linux.h"
6 6
7 #include <dirent.h>
7 #include <stdint.h> 8 #include <stdint.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <sys/uio.h>
12 #include <unistd.h>
8 13
9 #include <unistd.h> 14 #include <vector>
10 #include <sys/uio.h>
11 #include <sys/socket.h>
12 15
13 #include "base/eintr_wrapper.h" 16 #include "base/eintr_wrapper.h"
14 #include "base/format_macros.h" 17 #include "base/format_macros.h"
15 #include "base/logging.h" 18 #include "base/logging.h"
16 #include "base/message_loop.h" 19 #include "base/message_loop.h"
17 #include "base/rand_util.h" 20 #include "base/rand_util.h"
18 #include "base/string_util.h" 21 #include "base/string_util.h"
19 #include "breakpad/linux/exception_handler.h" 22 #include "breakpad/linux/exception_handler.h"
20 #include "breakpad/linux/linux_dumper.h" 23 #include "breakpad/linux/linux_dumper.h"
21 #include "breakpad/linux/minidump_writer.h" 24 #include "breakpad/linux/minidump_writer.h"
22 #include "chrome/app/breakpad_linux.h" 25 #include "chrome/app/breakpad_linux.h"
23 #include "chrome/browser/chrome_thread.h" 26 #include "chrome/browser/chrome_thread.h"
24 27
28 // expected prefix of the target of the /proc/self/fd/%d link for a socket
29 static const char kSocketLinkPrefix[] = "socket:[";
30
31 // Parse a symlink in /proc/pid/fd/$x and return the inode number of the
32 // socket.
33 // inode_out: (output) set to the inode number on success
34 // path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
35 // log: if true, log messages about failure details
36 static bool ProcPathGetInode(unsigned* inode_out, const char* path,
37 bool log = false) {
38 char buf[256];
39 const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
40 if (n == -1) {
41 if (log) {
42 LOG(WARNING) << "Failed to read the inode number for a socket from /proc"
43 "(" << errno << ")";
44 }
45 return false;
46 }
47 buf[n] = 0;
48
49 if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
50 if (log) {
51 LOG(WARNING) << "The descriptor passed from the crashing process wasn't a"
52 " UNIX domain socket.";
53 }
54 return false;
55 }
56
57 char *endptr;
58 const unsigned long int inode_ul =
59 strtoul(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10);
60 if (*endptr != ']')
61 return false;
62
63 if (inode_ul == ULONG_MAX || inode_ul > UINT_MAX) {
64 if (log) {
65 LOG(WARNING) << "Failed to parse a socket's inode number: the number was "
66 "too large. Please report this bug: " << buf;
67 }
68 return false;
69 }
70
71 *inode_out = inode_ul;
72 return true;
73 }
74
75 // Return the inode number for the UNIX domain socket |fd|.
76 static bool FileDescriptorGetInode(unsigned* inode_out, int fd) {
77 char path[256];
78 if (snprintf(path, sizeof(path), "/proc/self/fd/%d", fd) < 0)
79 return false;
80
81 return ProcPathGetInode(inode_out, path, true);
82 }
83
84 // Find the process which holds the given socket, named by inode number. If
85 // multiple processes hold the socket, this function returns false.
86 static bool FindProcessHoldingSocket(pid_t* pid_out, unsigned socket_inode) {
87 bool already_found = false;
88
89 DIR* proc = opendir("/proc");
90 if (!proc) {
91 LOG(WARNING) << "Cannot open /proc";
92 return false;
93 }
94
95 std::vector<pid_t> pids;
96
97 struct dirent* dent;
98 while ((dent = readdir(proc))) {
99 char *endptr;
100 const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10);
101 if (pid_ul == ULONG_MAX || *endptr)
102 continue;
103 pids.push_back(pid_ul);
104 }
105 closedir(proc);
106
107 for (std::vector<pid_t>::const_iterator
108 i = pids.begin(); i != pids.end(); ++i) {
109 const pid_t current_pid = *i;
110 char buf[256];
111 if (snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid) < 0)
112 continue;
113 DIR* fd = opendir(buf);
114 if (!fd)
115 continue;
116
117 while ((dent = readdir(fd))) {
118 if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid,
119 dent->d_name) < 0) {
120 continue;
121 }
122
123 unsigned fd_inode;
124 if (ProcPathGetInode(&fd_inode, buf)) {
125 if (fd_inode == socket_inode) {
126 if (already_found) {
127 closedir(fd);
128 return false;
129 }
130
131 already_found = true;
132 *pid_out = current_pid;
133 break;
134 }
135 }
136 }
137
138 closedir(fd);
139 }
140
141 return already_found;
142 }
143
25 // Since RenderCrashHandlerHostLinux is a singleton, it's only destroyed at the 144 // Since RenderCrashHandlerHostLinux is a singleton, it's only destroyed at the
26 // end of the processes lifetime, which is greater in span then the lifetime of 145 // end of the processes lifetime, which is greater in span then the lifetime of
27 // the IO message loop. 146 // the IO message loop.
28 template<> struct RunnableMethodTraits<RenderCrashHandlerHostLinux> { 147 template<> struct RunnableMethodTraits<RenderCrashHandlerHostLinux> {
29 static void RetainCallee(RenderCrashHandlerHostLinux*) { } 148 static void RetainCallee(RenderCrashHandlerHostLinux*) { }
30 static void ReleaseCallee(RenderCrashHandlerHostLinux*) { } 149 static void ReleaseCallee(RenderCrashHandlerHostLinux*) { }
31 }; 150 };
32 151
33 RenderCrashHandlerHostLinux::RenderCrashHandlerHostLinux() 152 RenderCrashHandlerHostLinux::RenderCrashHandlerHostLinux()
34 : renderer_socket_(-1), 153 : renderer_socket_(-1),
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 } 273 }
155 274
156 if (crashing_pid == -1 || signal_fd == -1) { 275 if (crashing_pid == -1 || signal_fd == -1) {
157 LOG(ERROR) << "Death signal message didn't contain all expected control" 276 LOG(ERROR) << "Death signal message didn't contain all expected control"
158 << " messages"; 277 << " messages";
159 if (signal_fd) 278 if (signal_fd)
160 HANDLE_EINTR(close(signal_fd)); 279 HANDLE_EINTR(close(signal_fd));
161 return; 280 return;
162 } 281 }
163 282
283 // Kernel bug workaround (broken in 2.6.30 at least):
284 // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
285 // namespaces. Thus |crashing_pid| might be garbage from our point of view.
286 // In the future we can remove this workaround, but we have to wait a couple
287 // of years to be sure that it's worked its way out into the world.
288
289 unsigned inode_number;
290 if (!FileDescriptorGetInode(&inode_number, signal_fd)) {
291 LOG(WARNING) << "Failed to get inode number for passed socket";
292 HANDLE_EINTR(close(signal_fd));
293 return;
294 }
295
296 if (!FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) {
297 LOG(WARNING) << "Failed to find process holding other end of crash reply "
298 "socket";
299 HANDLE_EINTR(close(signal_fd));
300 return;
301 }
302
164 const uint64 rand = base::RandUint64(); 303 const uint64 rand = base::RandUint64();
165 const std::string minidump_filename = 304 const std::string minidump_filename =
166 StringPrintf("/tmp/chromium-renderer-minidump-%016" PRIx64 ".dmp", rand); 305 StringPrintf("/tmp/chromium-renderer-minidump-%016" PRIx64 ".dmp", rand);
167 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), 306 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
168 crashing_pid, context, 307 crashing_pid, context,
169 kCrashContextSize)) { 308 kCrashContextSize)) {
170 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; 309 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
171 HANDLE_EINTR(close(signal_fd)); 310 HANDLE_EINTR(close(signal_fd));
172 } 311 }
173 312
174 // Send the done signal to the renderer: it can exit now. 313 // Send the done signal to the renderer: it can exit now.
175 memset(&msg, 0, sizeof(msg)); 314 memset(&msg, 0, sizeof(msg));
176 iov.iov_base = const_cast<char*>("\x42"); 315 iov.iov_base = const_cast<char*>("\x42");
177 iov.iov_len = 1; 316 iov.iov_len = 1;
178 msg.msg_iov = &iov; 317 msg.msg_iov = &iov;
179 msg.msg_iovlen = 1; 318 msg.msg_iovlen = 1;
180 319
181 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); 320 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
182 HANDLE_EINTR(close(signal_fd)); 321 HANDLE_EINTR(close(signal_fd));
183 322
184 UploadCrashDump(minidump_filename.c_str(), 323 UploadCrashDump(minidump_filename.c_str(),
185 "renderer", 8, 324 "renderer", 8,
186 crash_url, crash_url_len, 325 crash_url, crash_url_len,
187 guid, kGuidSize); 326 guid, kGuidSize);
188 } 327 }
189 328
190 void RenderCrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { 329 void RenderCrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
191 file_descriptor_watcher_.StopWatchingFileDescriptor(); 330 file_descriptor_watcher_.StopWatchingFileDescriptor();
192 } 331 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/browser_render_process_host.cc ('k') | chrome/browser/zygote_host_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698