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.
5 #include "content/browser/renderer_host/sandbox_ipc_linux.h"
9 #include <sys/socket.h>
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"
36 using blink::WebCString
;
37 using blink::WebFontInfo
;
38 using blink::WebUChar
;
39 using blink::WebUChar32
;
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
) {
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;
54 NOTREACHED() << "Unexpected hinting value " << hinting
;
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
) {
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;
70 NOTREACHED() << "Unexpected subpixel rendering value " << rendering
;
76 SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd
, int browser_socket
)
77 : lifeline_fd_(lifeline_fd
),
78 browser_socket_(browser_socket
) {
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
;
91 HANDLE_EINTR(poll(pfds
, arraysize(pfds
), -1 /* no timeout */));
92 // '0' is not a possible return value with no timeout.
95 PLOG(WARNING
) << "poll";
96 if (failed_polls
++ == 3) {
97 LOG(FATAL
) << "poll(2) failing. SandboxIPCHandler aborting.";
105 // The browser process will close the other end of this pipe on shutdown,
106 // so we should exit.
107 if (pfds
[0].revents
) {
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
)) {
117 if (pfds
[1].revents
& POLLIN
) {
118 HandleRequestFromRenderer(browser_socket_
);
122 VLOG(1) << "SandboxIPCHandler stopping.";
125 void SandboxIPCHandler::HandleRequestFromRenderer(int fd
) {
126 ScopedVector
<base::ScopedFD
> fds
;
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];
134 const ssize_t len
= UnixDomainSocket::RecvMsg(fd
, buf
, sizeof(buf
), &fds
);
136 // TODO: should send an error reply, or the sender might block forever.
137 NOTREACHED() << "Sandbox host message is larger than kMaxFontFamilyLength";
143 Pickle
pickle(buf
, len
);
144 PickleIterator
iter(pickle
);
147 if (!pickle
.ReadInt(&iter
, &kind
))
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());
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
])
173 *paths_
.append() = new SkString(path
);
177 void SandboxIPCHandler::HandleFontMatchRequest(
179 const Pickle
& pickle
,
181 const std::vector
<base::ScopedFD
*>& fds
) {
182 uint32_t requested_style
;
184 if (!pickle
.ReadString(&iter
, &family
) ||
185 !pickle
.ReadUInt32(&iter
, &requested_style
))
188 SkFontConfigInterface::FontIdentity result_identity
;
189 SkString result_family
;
190 SkTypeface::Style result_style
;
191 SkFontConfigInterface
* fc
=
192 SkFontConfigInterface::GetSingletonDirectInterface();
194 fc
->matchFamilyName(family
.c_str(),
195 static_cast<SkTypeface::Style
>(requested_style
),
202 reply
.WriteBool(false);
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
);
209 reply
.WriteBool(true);
210 skia::WriteSkString(&reply
, result_family
);
211 skia::WriteSkFontIdentity(&reply
, result_identity
);
212 reply
.WriteUInt32(result_style
);
214 SendRendererReply(fds
, reply
, -1);
217 void SandboxIPCHandler::HandleFontOpenRequest(
219 const Pickle
& pickle
,
221 const std::vector
<base::ScopedFD
*>& fds
) {
223 if (!pickle
.ReadUInt32(&iter
, &index
))
225 if (index
>= static_cast<uint32_t>(paths_
.count()))
227 const int result_fd
= open(paths_
[index
]->c_str(), O_RDONLY
);
230 if (result_fd
== -1) {
231 reply
.WriteBool(false);
233 reply
.WriteBool(true);
236 // The receiver will have its own access to the file, so we will close it
238 SendRendererReply(fds
, reply
, result_fd
);
240 if (result_fd
>= 0) {
241 int err
= IGNORE_EINTR(close(result_fd
));
246 void SandboxIPCHandler::HandleGetFallbackFontForChar(
248 const Pickle
& pickle
,
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
254 EnsureWebKitInitialized();
256 if (!pickle
.ReadInt(&iter
, &c
))
259 std::string preferred_locale
;
260 if (!pickle
.ReadString(&iter
, &preferred_locale
))
263 blink::WebFallbackFont fallbackFont
;
264 WebFontInfo::fallbackFontForChar(c
, preferred_locale
.c_str(), &fallbackFont
);
266 int pathIndex
= FindOrAddPath(SkString(fallbackFont
.filename
.data()));
267 fallbackFont
.fontconfigInterfaceId
= pathIndex
;
270 if (fallbackFont
.name
.data()) {
271 reply
.WriteString(fallbackFont
.name
.data());
273 reply
.WriteString(std::string());
275 if (fallbackFont
.filename
.data()) {
276 reply
.WriteString(fallbackFont
.filename
.data());
278 reply
.WriteString(std::string());
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);
287 void SandboxIPCHandler::HandleGetStyleForStrike(
289 const Pickle
& pickle
,
291 const std::vector
<base::ScopedFD
*>& fds
) {
296 if (!pickle
.ReadString(&iter
, &family
) ||
297 !pickle
.ReadBool(&iter
, &bold
) ||
298 !pickle
.ReadBool(&iter
, &italic
) ||
299 !pickle
.ReadUInt16(&iter
, &pixel_size
)) {
303 EnsureWebKitInitialized();
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
);
312 // These are passed as ints since they're interpreted as tri-state chars in
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
);
323 SendRendererReply(fds
, reply
, -1);
326 void SandboxIPCHandler::HandleLocaltime(
328 const Pickle
& pickle
,
330 const std::vector
<base::ScopedFD
*>& fds
) {
331 // The other side of this call is in zygote_main_linux.cc
333 std::string time_string
;
334 if (!pickle
.ReadString(&iter
, &time_string
) ||
335 time_string
.size() != sizeof(time_t)) {
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
);
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
),
350 time_zone_string
= expanded_time
->tm_zone
;
354 reply
.WriteString(result_string
);
355 reply
.WriteString(time_zone_string
);
356 SendRendererReply(fds
, reply
, -1);
359 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
361 const Pickle
& pickle
,
363 const std::vector
<base::ScopedFD
*>& fds
) {
364 base::SharedMemoryCreateOptions options
;
366 if (!pickle
.ReadUInt32(&iter
, &size
))
369 if (!pickle
.ReadBool(&iter
, &options
.executable
))
372 base::SharedMemory shm
;
373 if (shm
.Create(options
))
374 shm_fd
= shm
.handle().fd
;
376 SendRendererReply(fds
, reply
, shm_fd
);
379 void SandboxIPCHandler::HandleMatchWithFallback(
381 const Pickle
& pickle
,
383 const std::vector
<base::ScopedFD
*>& fds
) {
385 bool is_bold
, is_italic
;
386 uint32 charset
, fallback_family
;
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
)) {
396 int font_fd
= MatchFontFaceWithFallback(
397 face
, is_bold
, is_italic
, charset
, fallback_family
);
400 SendRendererReply(fds
, reply
, font_fd
);
403 if (IGNORE_EINTR(close(font_fd
)) < 0)
404 PLOG(ERROR
) << "close";
408 void SandboxIPCHandler::SendRendererReply(
409 const std::vector
<base::ScopedFD
*>& fds
,
413 memset(&msg
, 0, sizeof(msg
));
414 struct iovec iov
= {const_cast<void*>(reply
.data()), reply
.size()};
418 char control_buffer
[CMSG_SPACE(sizeof(int))];
420 if (reply_fd
!= -1) {
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.
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
;
440 if (HANDLE_EINTR(sendmsg(fds
[0]->get(), &msg
, MSG_DONTWAIT
)) < 0)
441 PLOG(ERROR
) << "sendmsg";
444 SandboxIPCHandler::~SandboxIPCHandler() {
446 if (webkit_platform_support_
)
447 blink::shutdownWithoutV8();
449 if (IGNORE_EINTR(close(lifeline_fd_
)) < 0)
450 PLOG(ERROR
) << "close";
451 if (IGNORE_EINTR(close(browser_socket_
)) < 0)
452 PLOG(ERROR
) << "close";
455 void SandboxIPCHandler::EnsureWebKitInitialized() {
456 if (webkit_platform_support_
)
458 webkit_platform_support_
.reset(new BlinkPlatformImpl
);
459 blink::initializeWithoutV8(webkit_platform_support_
.get());
462 } // namespace content