Home | History | Annotate | Download | only in renderer_host
      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