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 3 // found in the LICENSE file. 4 5 #include "content/browser/renderer_host/render_sandbox_host_linux.h" 6 7 #include <fcntl.h> 8 #include <fontconfig/fontconfig.h> 9 #include <stdint.h> 10 #include <sys/poll.h> 11 #include <sys/socket.h> 12 #include <sys/stat.h> 13 #include <sys/uio.h> 14 #include <time.h> 15 #include <unistd.h> 16 17 #include <vector> 18 19 #include "base/command_line.h" 20 #include "base/linux_util.h" 21 #include "base/memory/scoped_ptr.h" 22 #include "base/memory/shared_memory.h" 23 #include "base/memory/singleton.h" 24 #include "base/pickle.h" 25 #include "base/posix/eintr_wrapper.h" 26 #include "base/posix/unix_domain_socket_linux.h" 27 #include "base/process/launch.h" 28 #include "base/process/process_metrics.h" 29 #include "base/strings/string_number_conversions.h" 30 #include "base/strings/string_util.h" 31 #include "content/child/webkitplatformsupport_impl.h" 32 #include "content/common/font_config_ipc_linux.h" 33 #include "content/common/sandbox_linux/sandbox_linux.h" 34 #include "content/common/set_process_title.h" 35 #include "content/public/common/content_switches.h" 36 #include "skia/ext/skia_utils_base.h" 37 #include "third_party/WebKit/public/platform/linux/WebFontInfo.h" 38 #include "third_party/WebKit/public/web/WebKit.h" 39 #include "third_party/npapi/bindings/npapi_extensions.h" 40 #include "third_party/skia/include/ports/SkFontConfigInterface.h" 41 #include "ui/gfx/font_render_params_linux.h" 42 43 using blink::WebCString; 44 using blink::WebFontInfo; 45 using blink::WebUChar; 46 using blink::WebUChar32; 47 48 namespace content { 49 50 // http://code.google.com/p/chromium/wiki/LinuxSandboxIPC 51 52 // BEWARE: code in this file run across *processes* (not just threads). 53 54 // This code runs in a child process 55 class SandboxIPCProcess { 56 public: 57 // lifeline_fd: this is the read end of a pipe which the browser process 58 // holds the other end of. If the browser process dies, its descriptors are 59 // closed and we will noticed an EOF on the pipe. That's our signal to exit. 60 // browser_socket: the browser's end of the sandbox IPC socketpair. From the 61 // point of view of the renderer, it's talking to the browser but this 62 // object actually services the requests. 63 // sandbox_cmd: the path of the sandbox executable 64 SandboxIPCProcess(int lifeline_fd, int browser_socket, 65 std::string sandbox_cmd) 66 : lifeline_fd_(lifeline_fd), 67 browser_socket_(browser_socket) { 68 if (!sandbox_cmd.empty()) { 69 sandbox_cmd_.push_back(sandbox_cmd); 70 sandbox_cmd_.push_back(base::kFindInodeSwitch); 71 } 72 73 // FontConfig doesn't provide a standard property to control subpixel 74 // positioning, so we pass the current setting through to WebKit. 75 WebFontInfo::setSubpixelPositioning( 76 gfx::GetDefaultWebkitSubpixelPositioning()); 77 78 CommandLine& command_line = *CommandLine::ForCurrentProcess(); 79 command_line.AppendSwitchASCII(switches::kProcessType, 80 switches::kSandboxIPCProcess); 81 82 // Update the process title. The argv was already cached by the call to 83 // SetProcessTitleFromCommandLine in content_main_runner.cc, so we can pass 84 // NULL here (we don't have the original argv at this point). 85 SetProcessTitleFromCommandLine(NULL); 86 } 87 88 ~SandboxIPCProcess(); 89 90 void Run() { 91 struct pollfd pfds[2]; 92 pfds[0].fd = lifeline_fd_; 93 pfds[0].events = POLLIN; 94 pfds[1].fd = browser_socket_; 95 pfds[1].events = POLLIN; 96 97 int failed_polls = 0; 98 for (;;) { 99 const int r = HANDLE_EINTR(poll(pfds, 2, -1)); 100 if (r < 1) { 101 LOG(WARNING) << "poll errno:" << errno; 102 if (failed_polls++ == 3) { 103 LOG(FATAL) << "poll failing. Sandbox host aborting."; 104 return; 105 } 106 continue; 107 } 108 109 failed_polls = 0; 110 111 if (pfds[0].revents) { 112 // our parent died so we should too. 113 _exit(0); 114 } 115 116 if (pfds[1].revents) { 117 HandleRequestFromRenderer(browser_socket_); 118 } 119 } 120 } 121 122 private: 123 void EnsureWebKitInitialized(); 124 125 // --------------------------------------------------------------------------- 126 // Requests from the renderer... 127 128 void HandleRequestFromRenderer(int fd) { 129 std::vector<int> fds; 130 131 // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength 132 // bytes long (this is the largest message type). 133 // 128 bytes padding are necessary so recvmsg() does not return MSG_TRUNC 134 // error for a maximum length message. 135 char buf[FontConfigIPC::kMaxFontFamilyLength + 128]; 136 137 const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); 138 if (len == -1) { 139 // TODO: should send an error reply, or the sender might block forever. 140 NOTREACHED() 141 << "Sandbox host message is larger than kMaxFontFamilyLength"; 142 return; 143 } 144 if (fds.empty()) 145 return; 146 147 Pickle pickle(buf, len); 148 PickleIterator iter(pickle); 149 150 int kind; 151 if (!pickle.ReadInt(&iter, &kind)) 152 goto error; 153 154 if (kind == FontConfigIPC::METHOD_MATCH) { 155 HandleFontMatchRequest(fd, pickle, iter, fds); 156 } else if (kind == FontConfigIPC::METHOD_OPEN) { 157 HandleFontOpenRequest(fd, pickle, iter, fds); 158 } else if (kind == LinuxSandbox::METHOD_GET_FONT_FAMILY_FOR_CHAR) { 159 HandleGetFontFamilyForChar(fd, pickle, iter, fds); 160 } else if (kind == LinuxSandbox::METHOD_LOCALTIME) { 161 HandleLocaltime(fd, pickle, iter, fds); 162 } else if (kind == LinuxSandbox::METHOD_GET_CHILD_WITH_INODE) { 163 HandleGetChildWithInode(fd, pickle, iter, fds); 164 } else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) { 165 HandleGetStyleForStrike(fd, pickle, iter, fds); 166 } else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) { 167 HandleMakeSharedMemorySegment(fd, pickle, iter, fds); 168 } else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) { 169 HandleMatchWithFallback(fd, pickle, iter, fds); 170 } 171 172 error: 173 for (std::vector<int>::const_iterator 174 i = fds.begin(); i != fds.end(); ++i) { 175 close(*i); 176 } 177 } 178 179 int FindOrAddPath(const SkString& path) { 180 int count = paths_.count(); 181 for (int i = 0; i < count; ++i) { 182 if (path == *paths_[i]) 183 return i; 184 } 185 *paths_.append() = new SkString(path); 186 return count; 187 } 188 189 void HandleFontMatchRequest(int fd, const Pickle& pickle, PickleIterator iter, 190 std::vector<int>& fds) { 191 uint32_t requested_style; 192 std::string family; 193 if (!pickle.ReadString(&iter, &family) || 194 !pickle.ReadUInt32(&iter, &requested_style)) 195 return; 196 197 SkFontConfigInterface::FontIdentity result_identity; 198 SkString result_family; 199 SkTypeface::Style result_style; 200 SkFontConfigInterface* fc = 201 SkFontConfigInterface::GetSingletonDirectInterface(); 202 const bool r = fc->matchFamilyName( 203 family.c_str(), static_cast<SkTypeface::Style>(requested_style), 204 &result_identity, &result_family, &result_style); 205 206 Pickle reply; 207 if (!r) { 208 reply.WriteBool(false); 209 } else { 210 // Stash away the returned path, so we can give it an ID (index) 211 // which will later be given to us in a request to open the file. 212 int index = FindOrAddPath(result_identity.fString); 213 result_identity.fID = static_cast<uint32_t>(index); 214 215 reply.WriteBool(true); 216 skia::WriteSkString(&reply, result_family); 217 skia::WriteSkFontIdentity(&reply, result_identity); 218 reply.WriteUInt32(result_style); 219 } 220 SendRendererReply(fds, reply, -1); 221 } 222 223 void HandleFontOpenRequest(int fd, const Pickle& pickle, PickleIterator iter, 224 std::vector<int>& fds) { 225 uint32_t index; 226 if (!pickle.ReadUInt32(&iter, &index)) 227 return; 228 if (index >= static_cast<uint32_t>(paths_.count())) 229 return; 230 const int result_fd = open(paths_[index]->c_str(), O_RDONLY); 231 232 Pickle reply; 233 if (result_fd == -1) { 234 reply.WriteBool(false); 235 } else { 236 reply.WriteBool(true); 237 } 238 239 // The receiver will have its own access to the file, so we will close it 240 // after this send. 241 SendRendererReply(fds, reply, result_fd); 242 243 if (result_fd >= 0) { 244 int err = IGNORE_EINTR(close(result_fd)); 245 DCHECK(!err); 246 } 247 } 248 249 void HandleGetFontFamilyForChar(int fd, const Pickle& pickle, 250 PickleIterator iter, 251 std::vector<int>& fds) { 252 // The other side of this call is 253 // chrome/renderer/renderer_sandbox_support_linux.cc 254 255 EnsureWebKitInitialized(); 256 WebUChar32 c; 257 if (!pickle.ReadInt(&iter, &c)) 258 return; 259 260 std::string preferred_locale; 261 if (!pickle.ReadString(&iter, &preferred_locale)) 262 return; 263 264 blink::WebFontFamily family; 265 WebFontInfo::familyForChar(c, preferred_locale.c_str(), &family); 266 267 Pickle reply; 268 if (family.name.data()) { 269 reply.WriteString(family.name.data()); 270 } else { 271 reply.WriteString(std::string()); 272 } 273 reply.WriteBool(family.isBold); 274 reply.WriteBool(family.isItalic); 275 SendRendererReply(fds, reply, -1); 276 } 277 278 void HandleGetStyleForStrike(int fd, const Pickle& pickle, 279 PickleIterator iter, 280 std::vector<int>& fds) { 281 std::string family; 282 int sizeAndStyle; 283 284 if (!pickle.ReadString(&iter, &family) || 285 !pickle.ReadInt(&iter, &sizeAndStyle)) { 286 return; 287 } 288 289 EnsureWebKitInitialized(); 290 blink::WebFontRenderStyle style; 291 WebFontInfo::renderStyleForStrike(family.c_str(), sizeAndStyle, &style); 292 293 Pickle reply; 294 reply.WriteInt(style.useBitmaps); 295 reply.WriteInt(style.useAutoHint); 296 reply.WriteInt(style.useHinting); 297 reply.WriteInt(style.hintStyle); 298 reply.WriteInt(style.useAntiAlias); 299 reply.WriteInt(style.useSubpixelRendering); 300 reply.WriteInt(style.useSubpixelPositioning); 301 302 SendRendererReply(fds, reply, -1); 303 } 304 305 void HandleLocaltime(int fd, const Pickle& pickle, PickleIterator iter, 306 std::vector<int>& fds) { 307 // The other side of this call is in zygote_main_linux.cc 308 309 std::string time_string; 310 if (!pickle.ReadString(&iter, &time_string) || 311 time_string.size() != sizeof(time_t)) { 312 return; 313 } 314 315 time_t time; 316 memcpy(&time, time_string.data(), sizeof(time)); 317 // We use localtime here because we need the tm_zone field to be filled 318 // out. Since we are a single-threaded process, this is safe. 319 const struct tm* expanded_time = localtime(&time); 320 321 std::string result_string; 322 const char* time_zone_string = ""; 323 if (expanded_time != NULL) { 324 result_string = std::string(reinterpret_cast<const char*>(expanded_time), 325 sizeof(struct tm)); 326 time_zone_string = expanded_time->tm_zone; 327 } 328 329 Pickle reply; 330 reply.WriteString(result_string); 331 reply.WriteString(time_zone_string); 332 SendRendererReply(fds, reply, -1); 333 } 334 335 void HandleGetChildWithInode(int fd, const Pickle& pickle, 336 PickleIterator iter, 337 std::vector<int>& fds) { 338 // The other side of this call is in zygote_main_linux.cc 339 if (sandbox_cmd_.empty()) { 340 LOG(ERROR) << "Not in the sandbox, this should not be called"; 341 return; 342 } 343 344 uint64_t inode; 345 if (!pickle.ReadUInt64(&iter, &inode)) 346 return; 347 348 base::ProcessId pid = 0; 349 std::string inode_output; 350 351 std::vector<std::string> sandbox_cmd = sandbox_cmd_; 352 sandbox_cmd.push_back(base::Int64ToString(inode)); 353 CommandLine get_inode_cmd(sandbox_cmd); 354 if (base::GetAppOutput(get_inode_cmd, &inode_output)) 355 base::StringToInt(inode_output, &pid); 356 357 if (!pid) { 358 // Even though the pid is invalid, we still need to reply to the zygote 359 // and not just return here. 360 LOG(ERROR) << "Could not get pid"; 361 } 362 363 Pickle reply; 364 reply.WriteInt(pid); 365 SendRendererReply(fds, reply, -1); 366 } 367 368 void HandleMakeSharedMemorySegment(int fd, const Pickle& pickle, 369 PickleIterator iter, 370 std::vector<int>& fds) { 371 base::SharedMemoryCreateOptions options; 372 uint32_t size; 373 if (!pickle.ReadUInt32(&iter, &size)) 374 return; 375 options.size = size; 376 if (!pickle.ReadBool(&iter, &options.executable)) 377 return; 378 int shm_fd = -1; 379 base::SharedMemory shm; 380 if (shm.Create(options)) 381 shm_fd = shm.handle().fd; 382 Pickle reply; 383 SendRendererReply(fds, reply, shm_fd); 384 } 385 386 void HandleMatchWithFallback(int fd, const Pickle& pickle, 387 PickleIterator iter, 388 std::vector<int>& fds) { 389 // Unlike the other calls, for which we are an indirection in front of 390 // WebKit or Skia, this call is always made via this sandbox helper 391 // process. Therefore the fontconfig code goes in here directly. 392 393 std::string face; 394 bool is_bold, is_italic; 395 uint32 charset; 396 397 if (!pickle.ReadString(&iter, &face) || 398 face.empty() || 399 !pickle.ReadBool(&iter, &is_bold) || 400 !pickle.ReadBool(&iter, &is_italic) || 401 !pickle.ReadUInt32(&iter, &charset)) { 402 return; 403 } 404 405 FcLangSet* langset = FcLangSetCreate(); 406 MSCharSetToFontconfig(langset, charset); 407 408 FcPattern* pattern = FcPatternCreate(); 409 // TODO(agl): FC_FAMILy needs to change 410 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) face.c_str()); 411 if (is_bold) 412 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); 413 if (is_italic) 414 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); 415 FcPatternAddLangSet(pattern, FC_LANG, langset); 416 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); 417 FcConfigSubstitute(NULL, pattern, FcMatchPattern); 418 FcDefaultSubstitute(pattern); 419 420 FcResult result; 421 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); 422 int font_fd = -1; 423 int good_enough_index = -1; 424 bool good_enough_index_set = false; 425 426 if (font_set) { 427 for (int i = 0; i < font_set->nfont; ++i) { 428 FcPattern* current = font_set->fonts[i]; 429 430 // Older versions of fontconfig have a bug where they cannot select 431 // only scalable fonts so we have to manually filter the results. 432 FcBool is_scalable; 433 if (FcPatternGetBool(current, FC_SCALABLE, 0, 434 &is_scalable) != FcResultMatch || 435 !is_scalable) { 436 continue; 437 } 438 439 FcChar8* c_filename; 440 if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != 441 FcResultMatch) { 442 continue; 443 } 444 445 // We only want to return sfnt (TrueType) based fonts. We don't have a 446 // very good way of detecting this so we'll filter based on the 447 // filename. 448 bool is_sfnt = false; 449 static const char kSFNTExtensions[][5] = { 450 ".ttf", ".otc", ".TTF", ".ttc", "" 451 }; 452 const size_t filename_len = strlen(reinterpret_cast<char*>(c_filename)); 453 for (unsigned j = 0; ; j++) { 454 if (kSFNTExtensions[j][0] == 0) { 455 // None of the extensions matched. 456 break; 457 } 458 const size_t ext_len = strlen(kSFNTExtensions[j]); 459 if (filename_len > ext_len && 460 memcmp(c_filename + filename_len - ext_len, 461 kSFNTExtensions[j], ext_len) == 0) { 462 is_sfnt = true; 463 break; 464 } 465 } 466 467 if (!is_sfnt) 468 continue; 469 470 // This font is good enough to pass muster, but we might be able to do 471 // better with subsequent ones. 472 if (!good_enough_index_set) { 473 good_enough_index = i; 474 good_enough_index_set = true; 475 } 476 477 FcValue matrix; 478 bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0; 479 480 if (is_italic && have_matrix) { 481 // we asked for an italic font, but fontconfig is giving us a 482 // non-italic font with a transformation matrix. 483 continue; 484 } 485 486 FcValue embolden; 487 const bool have_embolden = 488 FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0; 489 490 if (is_bold && have_embolden) { 491 // we asked for a bold font, but fontconfig gave us a non-bold font 492 // and asked us to apply fake bolding. 493 continue; 494 } 495 496 font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY); 497 if (font_fd >= 0) 498 break; 499 } 500 } 501 502 if (font_fd == -1 && good_enough_index_set) { 503 // We didn't find a font that we liked, so we fallback to something 504 // acceptable. 505 FcPattern* current = font_set->fonts[good_enough_index]; 506 FcChar8* c_filename; 507 FcPatternGetString(current, FC_FILE, 0, &c_filename); 508 font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY); 509 } 510 511 if (font_set) 512 FcFontSetDestroy(font_set); 513 FcPatternDestroy(pattern); 514 515 Pickle reply; 516 SendRendererReply(fds, reply, font_fd); 517 518 if (font_fd >= 0) { 519 if (IGNORE_EINTR(close(font_fd)) < 0) 520 PLOG(ERROR) << "close"; 521 } 522 } 523 524 // MSCharSetToFontconfig translates a Microsoft charset identifier to a 525 // fontconfig language set by appending to |langset|. 526 static void MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) { 527 // We have need to translate raw fdwCharSet values into terms that 528 // fontconfig can understand. (See the description of fdwCharSet in the MSDN 529 // documentation for CreateFont: 530 // http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx ) 531 // 532 // Although the argument is /called/ 'charset', the actual values conflate 533 // character sets (which are sets of Unicode code points) and character 534 // encodings (which are algorithms for turning a series of bits into a 535 // series of code points.) Sometimes the values will name a language, 536 // sometimes they'll name an encoding. In the latter case I'm assuming that 537 // they mean the set of code points in the domain of that encoding. 538 // 539 // fontconfig deals with ISO 639-1 language codes: 540 // http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 541 // 542 // So, for each of the documented fdwCharSet values I've had to take a 543 // guess at the set of ISO 639-1 languages intended. 544 545 switch (fdwCharSet) { 546 case NPCharsetAnsi: 547 // These values I don't really know what to do with, so I'm going to map 548 // them to English also. 549 case NPCharsetDefault: 550 case NPCharsetMac: 551 case NPCharsetOEM: 552 case NPCharsetSymbol: 553 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en")); 554 break; 555 case NPCharsetBaltic: 556 // The three baltic languages. 557 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("et")); 558 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lv")); 559 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lt")); 560 break; 561 // TODO(jungshik): Would we be better off mapping Big5 to zh-tw 562 // and GB2312 to zh-cn? Fontconfig has 4 separate orthography 563 // files (zh-{cn,tw,hk,mo}. 564 case NPCharsetChineseBIG5: 565 case NPCharsetGB2312: 566 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh")); 567 break; 568 case NPCharsetEastEurope: 569 // A scattering of eastern European languages. 570 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl")); 571 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs")); 572 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk")); 573 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu")); 574 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr")); 575 break; 576 case NPCharsetGreek: 577 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el")); 578 break; 579 case NPCharsetHangul: 580 case NPCharsetJohab: 581 // Korean 582 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko")); 583 break; 584 case NPCharsetRussian: 585 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru")); 586 break; 587 case NPCharsetShiftJIS: 588 // Japanese 589 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja")); 590 break; 591 case NPCharsetTurkish: 592 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr")); 593 break; 594 case NPCharsetVietnamese: 595 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi")); 596 break; 597 case NPCharsetArabic: 598 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar")); 599 break; 600 case NPCharsetHebrew: 601 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he")); 602 break; 603 case NPCharsetThai: 604 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th")); 605 break; 606 // default: 607 // Don't add any languages in that case that we don't recognise the 608 // constant. 609 } 610 } 611 612 void SendRendererReply(const std::vector<int>& fds, const Pickle& reply, 613 int reply_fd) { 614 struct msghdr msg; 615 memset(&msg, 0, sizeof(msg)); 616 struct iovec iov = {const_cast<void*>(reply.data()), reply.size()}; 617 msg.msg_iov = &iov; 618 msg.msg_iovlen = 1; 619 620 char control_buffer[CMSG_SPACE(sizeof(int))]; 621 622 if (reply_fd != -1) { 623 struct stat st; 624 if (fstat(reply_fd, &st) == 0 && S_ISDIR(st.st_mode)) { 625 LOG(FATAL) << "Tried to send a directory descriptor over sandbox IPC"; 626 // We must never send directory descriptors to a sandboxed process 627 // because they can use openat with ".." elements in the path in order 628 // to escape the sandbox and reach the real filesystem. 629 } 630 631 struct cmsghdr *cmsg; 632 msg.msg_control = control_buffer; 633 msg.msg_controllen = sizeof(control_buffer); 634 cmsg = CMSG_FIRSTHDR(&msg); 635 cmsg->cmsg_level = SOL_SOCKET; 636 cmsg->cmsg_type = SCM_RIGHTS; 637 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 638 memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd)); 639 msg.msg_controllen = cmsg->cmsg_len; 640 } 641 642 if (HANDLE_EINTR(sendmsg(fds[0], &msg, MSG_DONTWAIT)) < 0) 643 PLOG(ERROR) << "sendmsg"; 644 } 645 646 // --------------------------------------------------------------------------- 647 648 const int lifeline_fd_; 649 const int browser_socket_; 650 std::vector<std::string> sandbox_cmd_; 651 scoped_ptr<WebKitPlatformSupportImpl> webkit_platform_support_; 652 SkTDArray<SkString*> paths_; 653 }; 654 655 SandboxIPCProcess::~SandboxIPCProcess() { 656 paths_.deleteAll(); 657 if (webkit_platform_support_) 658 blink::shutdownWithoutV8(); 659 } 660 661 void SandboxIPCProcess::EnsureWebKitInitialized() { 662 if (webkit_platform_support_) 663 return; 664 webkit_platform_support_.reset(new WebKitPlatformSupportImpl); 665 blink::initializeWithoutV8(webkit_platform_support_.get()); 666 } 667 668 // ----------------------------------------------------------------------------- 669 670 // Runs on the main thread at startup. 671 RenderSandboxHostLinux::RenderSandboxHostLinux() 672 : initialized_(false), 673 renderer_socket_(0), 674 childs_lifeline_fd_(0), 675 pid_(0) { 676 } 677 678 // static 679 RenderSandboxHostLinux* RenderSandboxHostLinux::GetInstance() { 680 return Singleton<RenderSandboxHostLinux>::get(); 681 } 682 683 void RenderSandboxHostLinux::Init(const std::string& sandbox_path) { 684 DCHECK(!initialized_); 685 initialized_ = true; 686 687 int fds[2]; 688 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the renderer from 689 // sending datagrams to other sockets on the system. The sandbox may prevent 690 // the renderer from calling socket() to create new sockets, but it'll still 691 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send 692 // a datagram to any (abstract) socket on the same system. With 693 // SOCK_SEQPACKET, this is prevented. 694 #if defined(OS_FREEBSD) || defined(OS_OPENBSD) 695 // The BSDs often don't support SOCK_SEQPACKET yet, so fall back to 696 // SOCK_DGRAM if necessary. 697 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) != 0) 698 CHECK(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == 0); 699 #else 700 CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0); 701 #endif 702 703 renderer_socket_ = fds[0]; 704 const int browser_socket = fds[1]; 705 706 int pipefds[2]; 707 CHECK(0 == pipe(pipefds)); 708 const int child_lifeline_fd = pipefds[0]; 709 childs_lifeline_fd_ = pipefds[1]; 710 711 // We need to be monothreaded before we fork(). 712 #if !defined(TOOLKIT_GTK) 713 // Exclude gtk port as TestSuite in base/tests/test_suite.cc is calling 714 // gtk_init. 715 // TODO(oshima): Remove ifdef when above issues are resolved. 716 DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle())); 717 #endif 718 pid_ = fork(); 719 if (pid_ == 0) { 720 if (IGNORE_EINTR(close(fds[0])) < 0) 721 DPLOG(ERROR) << "close"; 722 if (IGNORE_EINTR(close(pipefds[1])) < 0) 723 DPLOG(ERROR) << "close"; 724 725 SandboxIPCProcess handler(child_lifeline_fd, browser_socket, sandbox_path); 726 handler.Run(); 727 _exit(0); 728 } 729 } 730 731 RenderSandboxHostLinux::~RenderSandboxHostLinux() { 732 if (initialized_) { 733 if (IGNORE_EINTR(close(renderer_socket_)) < 0) 734 PLOG(ERROR) << "close"; 735 if (IGNORE_EINTR(close(childs_lifeline_fd_)) < 0) 736 PLOG(ERROR) << "close"; 737 } 738 } 739 740 } // namespace content 741