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