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