• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/renderer_host/render_sandbox_host_linux.h"
6 
7 #include <fcntl.h>
8 #include <fontconfig/fontconfig.h>
9 #include <stdint.h>
10 #include <sys/poll.h>
11 #include <sys/socket.h>
12 #include <sys/stat.h>
13 #include <sys/uio.h>
14 #include <time.h>
15 #include <unistd.h>
16 
17 #include <vector>
18 
19 #include "base/command_line.h"
20 #include "base/linux_util.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/memory/shared_memory.h"
23 #include "base/memory/singleton.h"
24 #include "base/pickle.h"
25 #include "base/posix/eintr_wrapper.h"
26 #include "base/posix/unix_domain_socket_linux.h"
27 #include "base/process/launch.h"
28 #include "base/process/process_metrics.h"
29 #include "base/strings/string_number_conversions.h"
30 #include "base/strings/string_util.h"
31 #include "content/child/webkitplatformsupport_impl.h"
32 #include "content/common/font_config_ipc_linux.h"
33 #include "content/common/sandbox_linux/sandbox_linux.h"
34 #include "content/common/set_process_title.h"
35 #include "content/public/common/content_switches.h"
36 #include "skia/ext/skia_utils_base.h"
37 #include "third_party/WebKit/public/platform/linux/WebFontInfo.h"
38 #include "third_party/WebKit/public/web/WebKit.h"
39 #include "third_party/npapi/bindings/npapi_extensions.h"
40 #include "third_party/skia/include/ports/SkFontConfigInterface.h"
41 #include "ui/gfx/font_render_params_linux.h"
42 
43 using blink::WebCString;
44 using blink::WebFontInfo;
45 using blink::WebUChar;
46 using blink::WebUChar32;
47 
48 namespace content {
49 
50 // http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
51 
52 // BEWARE: code in this file run across *processes* (not just threads).
53 
54 // This code runs in a child process
55 class SandboxIPCProcess  {
56  public:
57   // lifeline_fd: this is the read end of a pipe which the browser process
58   //   holds the other end of. If the browser process dies, its descriptors are
59   //   closed and we will noticed an EOF on the pipe. That's our signal to exit.
60   // browser_socket: the browser's end of the sandbox IPC socketpair. From the
61   //   point of view of the renderer, it's talking to the browser but this
62   //   object actually services the requests.
63   // sandbox_cmd: the path of the sandbox executable
SandboxIPCProcess(int lifeline_fd,int browser_socket,std::string sandbox_cmd)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 
Run()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 
HandleRequestFromRenderer(int fd)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 
FindOrAddPath(const SkString & path)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 
HandleFontMatchRequest(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleFontOpenRequest(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleGetFontFamilyForChar(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleGetStyleForStrike(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleLocaltime(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleGetChildWithInode(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleMakeSharedMemorySegment(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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 
HandleMatchWithFallback(int fd,const Pickle & pickle,PickleIterator iter,std::vector<int> & fds)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|.
MSCharSetToFontconfig(FcLangSet * langset,unsigned fdwCharSet)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 
SendRendererReply(const std::vector<int> & fds,const Pickle & reply,int reply_fd)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 
~SandboxIPCProcess()655 SandboxIPCProcess::~SandboxIPCProcess() {
656   paths_.deleteAll();
657   if (webkit_platform_support_)
658     blink::shutdownWithoutV8();
659 }
660 
EnsureWebKitInitialized()661 void SandboxIPCProcess::EnsureWebKitInitialized() {
662   if (webkit_platform_support_)
663     return;
664   webkit_platform_support_.reset(new WebKitPlatformSupportImpl);
665   blink::initializeWithoutV8(webkit_platform_support_.get());
666 }
667 
668 // -----------------------------------------------------------------------------
669 
670 // Runs on the main thread at startup.
RenderSandboxHostLinux()671 RenderSandboxHostLinux::RenderSandboxHostLinux()
672     : initialized_(false),
673       renderer_socket_(0),
674       childs_lifeline_fd_(0),
675       pid_(0) {
676 }
677 
678 // static
GetInstance()679 RenderSandboxHostLinux* RenderSandboxHostLinux::GetInstance() {
680   return Singleton<RenderSandboxHostLinux>::get();
681 }
682 
Init(const std::string & sandbox_path)683 void RenderSandboxHostLinux::Init(const std::string& sandbox_path) {
684   DCHECK(!initialized_);
685   initialized_ = true;
686 
687   int fds[2];
688   // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the renderer from
689   // sending datagrams to other sockets on the system. The sandbox may prevent
690   // the renderer from calling socket() to create new sockets, but it'll still
691   // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
692   // a datagram to any (abstract) socket on the same system. With
693   // SOCK_SEQPACKET, this is prevented.
694 #if defined(OS_FREEBSD) || defined(OS_OPENBSD)
695   // The BSDs often don't support SOCK_SEQPACKET yet, so fall back to
696   // SOCK_DGRAM if necessary.
697   if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) != 0)
698     CHECK(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) == 0);
699 #else
700   CHECK(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
701 #endif
702 
703   renderer_socket_ = fds[0];
704   const int browser_socket = fds[1];
705 
706   int pipefds[2];
707   CHECK(0 == pipe(pipefds));
708   const int child_lifeline_fd = pipefds[0];
709   childs_lifeline_fd_ = pipefds[1];
710 
711   // We need to be monothreaded before we fork().
712 #if !defined(TOOLKIT_GTK)
713   // Exclude gtk port as TestSuite in base/tests/test_suite.cc is calling
714   // gtk_init.
715   // TODO(oshima): Remove ifdef when above issues are resolved.
716   DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
717 #endif
718   pid_ = fork();
719   if (pid_ == 0) {
720     if (IGNORE_EINTR(close(fds[0])) < 0)
721       DPLOG(ERROR) << "close";
722     if (IGNORE_EINTR(close(pipefds[1])) < 0)
723       DPLOG(ERROR) << "close";
724 
725     SandboxIPCProcess handler(child_lifeline_fd, browser_socket, sandbox_path);
726     handler.Run();
727     _exit(0);
728   }
729 }
730 
~RenderSandboxHostLinux()731 RenderSandboxHostLinux::~RenderSandboxHostLinux() {
732   if (initialized_) {
733     if (IGNORE_EINTR(close(renderer_socket_)) < 0)
734       PLOG(ERROR) << "close";
735     if (IGNORE_EINTR(close(childs_lifeline_fd_)) < 0)
736       PLOG(ERROR) << "close";
737   }
738 }
739 
740 }  // namespace content
741