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