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
43using blink::WebCString;
44using blink::WebFontInfo;
45using blink::WebUChar;
46using blink::WebUChar32;
47
48namespace 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
55class 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
655SandboxIPCProcess::~SandboxIPCProcess() {
656  paths_.deleteAll();
657  if (webkit_platform_support_)
658    blink::shutdownWithoutV8();
659}
660
661void 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.
671RenderSandboxHostLinux::RenderSandboxHostLinux()
672    : initialized_(false),
673      renderer_socket_(0),
674      childs_lifeline_fd_(0),
675      pid_(0) {
676}
677
678// static
679RenderSandboxHostLinux* RenderSandboxHostLinux::GetInstance() {
680  return Singleton<RenderSandboxHostLinux>::get();
681}
682
683void 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
731RenderSandboxHostLinux::~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