Home | History | Annotate | Download | only in renderer_host
      1 // Copyright 2014 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/sandbox_ipc_linux.h"
      6 
      7 #include <fcntl.h>
      8 #include <sys/poll.h>
      9 #include <sys/socket.h>
     10 #include <sys/stat.h>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/command_line.h"
     14 #include "base/files/scoped_file.h"
     15 #include "base/linux_util.h"
     16 #include "base/macros.h"
     17 #include "base/memory/scoped_vector.h"
     18 #include "base/memory/shared_memory.h"
     19 #include "base/posix/eintr_wrapper.h"
     20 #include "base/posix/unix_domain_socket_linux.h"
     21 #include "base/process/launch.h"
     22 #include "base/strings/string_number_conversions.h"
     23 #include "content/browser/renderer_host/font_utils_linux.h"
     24 #include "content/common/font_config_ipc_linux.h"
     25 #include "content/common/sandbox_linux/sandbox_linux.h"
     26 #include "content/common/set_process_title.h"
     27 #include "content/public/common/content_switches.h"
     28 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
     29 #include "third_party/WebKit/public/platform/linux/WebFontInfo.h"
     30 #include "third_party/WebKit/public/web/WebKit.h"
     31 #include "third_party/npapi/bindings/npapi_extensions.h"
     32 #include "third_party/skia/include/ports/SkFontConfigInterface.h"
     33 #include "ui/gfx/font.h"
     34 #include "ui/gfx/font_render_params.h"
     35 
     36 using blink::WebCString;
     37 using blink::WebFontInfo;
     38 using blink::WebUChar;
     39 using blink::WebUChar32;
     40 
     41 namespace content {
     42 
     43 namespace {
     44 
     45 // Converts gfx::FontRenderParams::Hinting to WebFontRenderStyle::hintStyle.
     46 // Returns an int for serialization, but the underlying Blink type is a char.
     47 int ConvertHinting(gfx::FontRenderParams::Hinting hinting) {
     48   switch (hinting) {
     49     case gfx::FontRenderParams::HINTING_NONE:   return 0;
     50     case gfx::FontRenderParams::HINTING_SLIGHT: return 1;
     51     case gfx::FontRenderParams::HINTING_MEDIUM: return 2;
     52     case gfx::FontRenderParams::HINTING_FULL:   return 3;
     53   }
     54   NOTREACHED() << "Unexpected hinting value " << hinting;
     55   return 0;
     56 }
     57 
     58 // Converts gfx::FontRenderParams::SubpixelRendering to
     59 // WebFontRenderStyle::useSubpixelRendering. Returns an int for serialization,
     60 // but the underlying Blink type is a char.
     61 int ConvertSubpixelRendering(
     62     gfx::FontRenderParams::SubpixelRendering rendering) {
     63   switch (rendering) {
     64     case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE: return 0;
     65     case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:  return 1;
     66     case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:  return 1;
     67     case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB: return 1;
     68     case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR: return 1;
     69   }
     70   NOTREACHED() << "Unexpected subpixel rendering value " << rendering;
     71   return 0;
     72 }
     73 
     74 }  // namespace
     75 
     76 SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd, int browser_socket)
     77     : lifeline_fd_(lifeline_fd),
     78       browser_socket_(browser_socket) {
     79 }
     80 
     81 void SandboxIPCHandler::Run() {
     82   struct pollfd pfds[2];
     83   pfds[0].fd = lifeline_fd_;
     84   pfds[0].events = POLLIN;
     85   pfds[1].fd = browser_socket_;
     86   pfds[1].events = POLLIN;
     87 
     88   int failed_polls = 0;
     89   for (;;) {
     90     const int r =
     91         HANDLE_EINTR(poll(pfds, arraysize(pfds), -1 /* no timeout */));
     92     // '0' is not a possible return value with no timeout.
     93     DCHECK_NE(0, r);
     94     if (r < 0) {
     95       PLOG(WARNING) << "poll";
     96       if (failed_polls++ == 3) {
     97         LOG(FATAL) << "poll(2) failing. SandboxIPCHandler aborting.";
     98         return;
     99       }
    100       continue;
    101     }
    102 
    103     failed_polls = 0;
    104 
    105     // The browser process will close the other end of this pipe on shutdown,
    106     // so we should exit.
    107     if (pfds[0].revents) {
    108       break;
    109     }
    110 
    111     // If poll(2) reports an error condition in this fd,
    112     // we assume the zygote is gone and we exit the loop.
    113     if (pfds[1].revents & (POLLERR | POLLHUP)) {
    114       break;
    115     }
    116 
    117     if (pfds[1].revents & POLLIN) {
    118       HandleRequestFromRenderer(browser_socket_);
    119     }
    120   }
    121 
    122   VLOG(1) << "SandboxIPCHandler stopping.";
    123 }
    124 
    125 void SandboxIPCHandler::HandleRequestFromRenderer(int fd) {
    126   ScopedVector<base::ScopedFD> fds;
    127 
    128   // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength
    129   // bytes long (this is the largest message type).
    130   // 128 bytes padding are necessary so recvmsg() does not return MSG_TRUNC
    131   // error for a maximum length message.
    132   char buf[FontConfigIPC::kMaxFontFamilyLength + 128];
    133 
    134   const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
    135   if (len == -1) {
    136     // TODO: should send an error reply, or the sender might block forever.
    137     NOTREACHED() << "Sandbox host message is larger than kMaxFontFamilyLength";
    138     return;
    139   }
    140   if (fds.empty())
    141     return;
    142 
    143   Pickle pickle(buf, len);
    144   PickleIterator iter(pickle);
    145 
    146   int kind;
    147   if (!pickle.ReadInt(&iter, &kind))
    148     return;
    149 
    150   if (kind == FontConfigIPC::METHOD_MATCH) {
    151     HandleFontMatchRequest(fd, pickle, iter, fds.get());
    152   } else if (kind == FontConfigIPC::METHOD_OPEN) {
    153     HandleFontOpenRequest(fd, pickle, iter, fds.get());
    154   } else if (kind == LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR) {
    155     HandleGetFallbackFontForChar(fd, pickle, iter, fds.get());
    156   } else if (kind == LinuxSandbox::METHOD_LOCALTIME) {
    157     HandleLocaltime(fd, pickle, iter, fds.get());
    158   } else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) {
    159     HandleGetStyleForStrike(fd, pickle, iter, fds.get());
    160   } else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) {
    161     HandleMakeSharedMemorySegment(fd, pickle, iter, fds.get());
    162   } else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) {
    163     HandleMatchWithFallback(fd, pickle, iter, fds.get());
    164   }
    165 }
    166 
    167 int SandboxIPCHandler::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 SandboxIPCHandler::HandleFontMatchRequest(
    178     int fd,
    179     const Pickle& pickle,
    180     PickleIterator iter,
    181     const std::vector<base::ScopedFD*>& fds) {
    182   uint32_t requested_style;
    183   std::string family;
    184   if (!pickle.ReadString(&iter, &family) ||
    185       !pickle.ReadUInt32(&iter, &requested_style))
    186     return;
    187 
    188   SkFontConfigInterface::FontIdentity result_identity;
    189   SkString result_family;
    190   SkTypeface::Style result_style;
    191   SkFontConfigInterface* fc =
    192       SkFontConfigInterface::GetSingletonDirectInterface();
    193   const bool r =
    194       fc->matchFamilyName(family.c_str(),
    195                           static_cast<SkTypeface::Style>(requested_style),
    196                           &result_identity,
    197                           &result_family,
    198                           &result_style);
    199 
    200   Pickle reply;
    201   if (!r) {
    202     reply.WriteBool(false);
    203   } else {
    204     // Stash away the returned path, so we can give it an ID (index)
    205     // which will later be given to us in a request to open the file.
    206     int index = FindOrAddPath(result_identity.fString);
    207     result_identity.fID = static_cast<uint32_t>(index);
    208 
    209     reply.WriteBool(true);
    210     skia::WriteSkString(&reply, result_family);
    211     skia::WriteSkFontIdentity(&reply, result_identity);
    212     reply.WriteUInt32(result_style);
    213   }
    214   SendRendererReply(fds, reply, -1);
    215 }
    216 
    217 void SandboxIPCHandler::HandleFontOpenRequest(
    218     int fd,
    219     const Pickle& pickle,
    220     PickleIterator iter,
    221     const std::vector<base::ScopedFD*>& fds) {
    222   uint32_t index;
    223   if (!pickle.ReadUInt32(&iter, &index))
    224     return;
    225   if (index >= static_cast<uint32_t>(paths_.count()))
    226     return;
    227   const int result_fd = open(paths_[index]->c_str(), O_RDONLY);
    228 
    229   Pickle reply;
    230   if (result_fd == -1) {
    231     reply.WriteBool(false);
    232   } else {
    233     reply.WriteBool(true);
    234   }
    235 
    236   // The receiver will have its own access to the file, so we will close it
    237   // after this send.
    238   SendRendererReply(fds, reply, result_fd);
    239 
    240   if (result_fd >= 0) {
    241     int err = IGNORE_EINTR(close(result_fd));
    242     DCHECK(!err);
    243   }
    244 }
    245 
    246 void SandboxIPCHandler::HandleGetFallbackFontForChar(
    247     int fd,
    248     const Pickle& pickle,
    249     PickleIterator iter,
    250     const std::vector<base::ScopedFD*>& fds) {
    251   // The other side of this call is
    252   // content/common/child_process_sandbox_support_impl_linux.cc
    253 
    254   EnsureWebKitInitialized();
    255   WebUChar32 c;
    256   if (!pickle.ReadInt(&iter, &c))
    257     return;
    258 
    259   std::string preferred_locale;
    260   if (!pickle.ReadString(&iter, &preferred_locale))
    261     return;
    262 
    263   blink::WebFallbackFont fallbackFont;
    264   WebFontInfo::fallbackFontForChar(c, preferred_locale.c_str(), &fallbackFont);
    265 
    266   int pathIndex = FindOrAddPath(SkString(fallbackFont.filename.data()));
    267   fallbackFont.fontconfigInterfaceId = pathIndex;
    268 
    269   Pickle reply;
    270   if (fallbackFont.name.data()) {
    271     reply.WriteString(fallbackFont.name.data());
    272   } else {
    273     reply.WriteString(std::string());
    274   }
    275   if (fallbackFont.filename.data()) {
    276     reply.WriteString(fallbackFont.filename.data());
    277   } else {
    278     reply.WriteString(std::string());
    279   }
    280   reply.WriteInt(fallbackFont.fontconfigInterfaceId);
    281   reply.WriteInt(fallbackFont.ttcIndex);
    282   reply.WriteBool(fallbackFont.isBold);
    283   reply.WriteBool(fallbackFont.isItalic);
    284   SendRendererReply(fds, reply, -1);
    285 }
    286 
    287 void SandboxIPCHandler::HandleGetStyleForStrike(
    288     int fd,
    289     const Pickle& pickle,
    290     PickleIterator iter,
    291     const std::vector<base::ScopedFD*>& fds) {
    292   std::string family;
    293   bool bold, italic;
    294   uint16 pixel_size;
    295 
    296   if (!pickle.ReadString(&iter, &family) ||
    297       !pickle.ReadBool(&iter, &bold) ||
    298       !pickle.ReadBool(&iter, &italic) ||
    299       !pickle.ReadUInt16(&iter, &pixel_size)) {
    300     return;
    301   }
    302 
    303   EnsureWebKitInitialized();
    304 
    305   gfx::FontRenderParamsQuery query(true);
    306   query.families.push_back(family);
    307   query.pixel_size = pixel_size;
    308   query.style = gfx::Font::NORMAL |
    309       (bold ? gfx::Font::BOLD : 0) | (italic ? gfx::Font::ITALIC : 0);
    310   const gfx::FontRenderParams params = gfx::GetFontRenderParams(query, NULL);
    311 
    312   // These are passed as ints since they're interpreted as tri-state chars in
    313   // Blink.
    314   Pickle reply;
    315   reply.WriteInt(params.use_bitmaps);
    316   reply.WriteInt(params.autohinter);
    317   reply.WriteInt(params.hinting != gfx::FontRenderParams::HINTING_NONE);
    318   reply.WriteInt(ConvertHinting(params.hinting));
    319   reply.WriteInt(params.antialiasing);
    320   reply.WriteInt(ConvertSubpixelRendering(params.subpixel_rendering));
    321   reply.WriteInt(params.subpixel_positioning);
    322 
    323   SendRendererReply(fds, reply, -1);
    324 }
    325 
    326 void SandboxIPCHandler::HandleLocaltime(
    327     int fd,
    328     const Pickle& pickle,
    329     PickleIterator iter,
    330     const std::vector<base::ScopedFD*>& fds) {
    331   // The other side of this call is in zygote_main_linux.cc
    332 
    333   std::string time_string;
    334   if (!pickle.ReadString(&iter, &time_string) ||
    335       time_string.size() != sizeof(time_t)) {
    336     return;
    337   }
    338 
    339   time_t time;
    340   memcpy(&time, time_string.data(), sizeof(time));
    341   // We use localtime here because we need the tm_zone field to be filled
    342   // out. Since we are a single-threaded process, this is safe.
    343   const struct tm* expanded_time = localtime(&time);
    344 
    345   std::string result_string;
    346   const char* time_zone_string = "";
    347   if (expanded_time != NULL) {
    348     result_string = std::string(reinterpret_cast<const char*>(expanded_time),
    349                                 sizeof(struct tm));
    350     time_zone_string = expanded_time->tm_zone;
    351   }
    352 
    353   Pickle reply;
    354   reply.WriteString(result_string);
    355   reply.WriteString(time_zone_string);
    356   SendRendererReply(fds, reply, -1);
    357 }
    358 
    359 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
    360     int fd,
    361     const Pickle& pickle,
    362     PickleIterator iter,
    363     const std::vector<base::ScopedFD*>& fds) {
    364   base::SharedMemoryCreateOptions options;
    365   uint32_t size;
    366   if (!pickle.ReadUInt32(&iter, &size))
    367     return;
    368   options.size = size;
    369   if (!pickle.ReadBool(&iter, &options.executable))
    370     return;
    371   int shm_fd = -1;
    372   base::SharedMemory shm;
    373   if (shm.Create(options))
    374     shm_fd = shm.handle().fd;
    375   Pickle reply;
    376   SendRendererReply(fds, reply, shm_fd);
    377 }
    378 
    379 void SandboxIPCHandler::HandleMatchWithFallback(
    380     int fd,
    381     const Pickle& pickle,
    382     PickleIterator iter,
    383     const std::vector<base::ScopedFD*>& fds) {
    384   std::string face;
    385   bool is_bold, is_italic;
    386   uint32 charset, fallback_family;
    387 
    388   if (!pickle.ReadString(&iter, &face) || face.empty() ||
    389       !pickle.ReadBool(&iter, &is_bold) ||
    390       !pickle.ReadBool(&iter, &is_italic) ||
    391       !pickle.ReadUInt32(&iter, &charset) ||
    392       !pickle.ReadUInt32(&iter, &fallback_family)) {
    393     return;
    394   }
    395 
    396   int font_fd = MatchFontFaceWithFallback(
    397       face, is_bold, is_italic, charset, fallback_family);
    398 
    399   Pickle reply;
    400   SendRendererReply(fds, reply, font_fd);
    401 
    402   if (font_fd >= 0) {
    403     if (IGNORE_EINTR(close(font_fd)) < 0)
    404       PLOG(ERROR) << "close";
    405   }
    406 }
    407 
    408 void SandboxIPCHandler::SendRendererReply(
    409     const std::vector<base::ScopedFD*>& fds,
    410     const Pickle& reply,
    411     int reply_fd) {
    412   struct msghdr msg;
    413   memset(&msg, 0, sizeof(msg));
    414   struct iovec iov = {const_cast<void*>(reply.data()), reply.size()};
    415   msg.msg_iov = &iov;
    416   msg.msg_iovlen = 1;
    417 
    418   char control_buffer[CMSG_SPACE(sizeof(int))];
    419 
    420   if (reply_fd != -1) {
    421     struct stat st;
    422     if (fstat(reply_fd, &st) == 0 && S_ISDIR(st.st_mode)) {
    423       LOG(FATAL) << "Tried to send a directory descriptor over sandbox IPC";
    424       // We must never send directory descriptors to a sandboxed process
    425       // because they can use openat with ".." elements in the path in order
    426       // to escape the sandbox and reach the real filesystem.
    427     }
    428 
    429     struct cmsghdr* cmsg;
    430     msg.msg_control = control_buffer;
    431     msg.msg_controllen = sizeof(control_buffer);
    432     cmsg = CMSG_FIRSTHDR(&msg);
    433     cmsg->cmsg_level = SOL_SOCKET;
    434     cmsg->cmsg_type = SCM_RIGHTS;
    435     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    436     memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd));
    437     msg.msg_controllen = cmsg->cmsg_len;
    438   }
    439 
    440   if (HANDLE_EINTR(sendmsg(fds[0]->get(), &msg, MSG_DONTWAIT)) < 0)
    441     PLOG(ERROR) << "sendmsg";
    442 }
    443 
    444 SandboxIPCHandler::~SandboxIPCHandler() {
    445   paths_.deleteAll();
    446   if (webkit_platform_support_)
    447     blink::shutdownWithoutV8();
    448 
    449   if (IGNORE_EINTR(close(lifeline_fd_)) < 0)
    450     PLOG(ERROR) << "close";
    451   if (IGNORE_EINTR(close(browser_socket_)) < 0)
    452     PLOG(ERROR) << "close";
    453 }
    454 
    455 void SandboxIPCHandler::EnsureWebKitInitialized() {
    456   if (webkit_platform_support_)
    457     return;
    458   webkit_platform_support_.reset(new BlinkPlatformImpl);
    459   blink::initializeWithoutV8(webkit_platform_support_.get());
    460 }
    461 
    462 }  // namespace content
    463