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 (!iter
.ReadInt(&kind
))
150 if (kind
== FontConfigIPC::METHOD_MATCH
) {
151 HandleFontMatchRequest(fd
, iter
, fds
.get());
152 } else if (kind
== FontConfigIPC::METHOD_OPEN
) {
153 HandleFontOpenRequest(fd
, iter
, fds
.get());
154 } else if (kind
== LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR
) {
155 HandleGetFallbackFontForChar(fd
, iter
, fds
.get());
156 } else if (kind
== LinuxSandbox::METHOD_LOCALTIME
) {
157 HandleLocaltime(fd
, iter
, fds
.get());
158 } else if (kind
== LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE
) {
159 HandleGetStyleForStrike(fd
, iter
, fds
.get());
160 } else if (kind
== LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT
) {
161 HandleMakeSharedMemorySegment(fd
, iter
, fds
.get());
162 } else if (kind
== LinuxSandbox::METHOD_MATCH_WITH_FALLBACK
) {
163 HandleMatchWithFallback(fd
, 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(
180 const std::vector
<base::ScopedFD
*>& fds
) {
181 uint32_t requested_style
;
183 if (!iter
.ReadString(&family
) || !iter
.ReadUInt32(&requested_style
))
186 SkFontConfigInterface::FontIdentity result_identity
;
187 SkString result_family
;
188 SkTypeface::Style result_style
;
189 SkFontConfigInterface
* fc
=
190 SkFontConfigInterface::GetSingletonDirectInterface();
192 fc
->matchFamilyName(family
.c_str(),
193 static_cast<SkTypeface::Style
>(requested_style
),
200 reply
.WriteBool(false);
202 // Stash away the returned path, so we can give it an ID (index)
203 // which will later be given to us in a request to open the file.
204 int index
= FindOrAddPath(result_identity
.fString
);
205 result_identity
.fID
= static_cast<uint32_t>(index
);
207 reply
.WriteBool(true);
208 skia::WriteSkString(&reply
, result_family
);
209 skia::WriteSkFontIdentity(&reply
, result_identity
);
210 reply
.WriteUInt32(result_style
);
212 SendRendererReply(fds
, reply
, -1);
215 void SandboxIPCHandler::HandleFontOpenRequest(
218 const std::vector
<base::ScopedFD
*>& fds
) {
220 if (!iter
.ReadUInt32(&index
))
222 if (index
>= static_cast<uint32_t>(paths_
.count()))
224 const int result_fd
= open(paths_
[index
]->c_str(), O_RDONLY
);
227 if (result_fd
== -1) {
228 reply
.WriteBool(false);
230 reply
.WriteBool(true);
233 // The receiver will have its own access to the file, so we will close it
235 SendRendererReply(fds
, reply
, result_fd
);
237 if (result_fd
>= 0) {
238 int err
= IGNORE_EINTR(close(result_fd
));
243 void SandboxIPCHandler::HandleGetFallbackFontForChar(
246 const std::vector
<base::ScopedFD
*>& fds
) {
247 // The other side of this call is
248 // content/common/child_process_sandbox_support_impl_linux.cc
250 EnsureWebKitInitialized();
252 if (!iter
.ReadInt(&c
))
255 std::string preferred_locale
;
256 if (!iter
.ReadString(&preferred_locale
))
259 blink::WebFallbackFont fallbackFont
;
260 WebFontInfo::fallbackFontForChar(c
, preferred_locale
.c_str(), &fallbackFont
);
262 int pathIndex
= FindOrAddPath(SkString(fallbackFont
.filename
.data()));
263 fallbackFont
.fontconfigInterfaceId
= pathIndex
;
266 if (fallbackFont
.name
.data()) {
267 reply
.WriteString(fallbackFont
.name
.data());
269 reply
.WriteString(std::string());
271 if (fallbackFont
.filename
.data()) {
272 reply
.WriteString(fallbackFont
.filename
.data());
274 reply
.WriteString(std::string());
276 reply
.WriteInt(fallbackFont
.fontconfigInterfaceId
);
277 reply
.WriteInt(fallbackFont
.ttcIndex
);
278 reply
.WriteBool(fallbackFont
.isBold
);
279 reply
.WriteBool(fallbackFont
.isItalic
);
280 SendRendererReply(fds
, reply
, -1);
283 void SandboxIPCHandler::HandleGetStyleForStrike(
286 const std::vector
<base::ScopedFD
*>& fds
) {
291 if (!iter
.ReadString(&family
) ||
292 !iter
.ReadBool(&bold
) ||
293 !iter
.ReadBool(&italic
) ||
294 !iter
.ReadUInt16(&pixel_size
)) {
298 EnsureWebKitInitialized();
300 gfx::FontRenderParamsQuery query
;
301 query
.families
.push_back(family
);
302 query
.pixel_size
= pixel_size
;
303 query
.style
= gfx::Font::NORMAL
|
304 (bold
? gfx::Font::BOLD
: 0) | (italic
? gfx::Font::ITALIC
: 0);
305 const gfx::FontRenderParams params
= gfx::GetFontRenderParams(query
, NULL
);
307 // These are passed as ints since they're interpreted as tri-state chars in
310 reply
.WriteInt(params
.use_bitmaps
);
311 reply
.WriteInt(params
.autohinter
);
312 reply
.WriteInt(params
.hinting
!= gfx::FontRenderParams::HINTING_NONE
);
313 reply
.WriteInt(ConvertHinting(params
.hinting
));
314 reply
.WriteInt(params
.antialiasing
);
315 reply
.WriteInt(ConvertSubpixelRendering(params
.subpixel_rendering
));
316 reply
.WriteInt(params
.subpixel_positioning
);
318 SendRendererReply(fds
, reply
, -1);
321 void SandboxIPCHandler::HandleLocaltime(
324 const std::vector
<base::ScopedFD
*>& fds
) {
325 // The other side of this call is in zygote_main_linux.cc
327 std::string time_string
;
328 if (!iter
.ReadString(&time_string
) || time_string
.size() != sizeof(time_t))
332 memcpy(&time
, time_string
.data(), sizeof(time
));
333 // We use localtime here because we need the tm_zone field to be filled
334 // out. Since we are a single-threaded process, this is safe.
335 const struct tm
* expanded_time
= localtime(&time
);
337 std::string result_string
;
338 const char* time_zone_string
= "";
339 if (expanded_time
!= NULL
) {
340 result_string
= std::string(reinterpret_cast<const char*>(expanded_time
),
342 time_zone_string
= expanded_time
->tm_zone
;
346 reply
.WriteString(result_string
);
347 reply
.WriteString(time_zone_string
);
348 SendRendererReply(fds
, reply
, -1);
351 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
354 const std::vector
<base::ScopedFD
*>& fds
) {
355 base::SharedMemoryCreateOptions options
;
357 if (!iter
.ReadUInt32(&size
))
360 if (!iter
.ReadBool(&options
.executable
))
363 base::SharedMemory shm
;
364 if (shm
.Create(options
))
365 shm_fd
= shm
.handle().fd
;
367 SendRendererReply(fds
, reply
, shm_fd
);
370 void SandboxIPCHandler::HandleMatchWithFallback(
373 const std::vector
<base::ScopedFD
*>& fds
) {
375 bool is_bold
, is_italic
;
376 uint32 charset
, fallback_family
;
378 if (!iter
.ReadString(&face
) || face
.empty() ||
379 !iter
.ReadBool(&is_bold
) ||
380 !iter
.ReadBool(&is_italic
) ||
381 !iter
.ReadUInt32(&charset
) ||
382 !iter
.ReadUInt32(&fallback_family
)) {
386 int font_fd
= MatchFontFaceWithFallback(
387 face
, is_bold
, is_italic
, charset
, fallback_family
);
390 SendRendererReply(fds
, reply
, font_fd
);
393 if (IGNORE_EINTR(close(font_fd
)) < 0)
394 PLOG(ERROR
) << "close";
398 void SandboxIPCHandler::SendRendererReply(
399 const std::vector
<base::ScopedFD
*>& fds
,
403 memset(&msg
, 0, sizeof(msg
));
404 struct iovec iov
= {const_cast<void*>(reply
.data()), reply
.size()};
408 char control_buffer
[CMSG_SPACE(sizeof(int))];
410 if (reply_fd
!= -1) {
412 if (fstat(reply_fd
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
413 LOG(FATAL
) << "Tried to send a directory descriptor over sandbox IPC";
414 // We must never send directory descriptors to a sandboxed process
415 // because they can use openat with ".." elements in the path in order
416 // to escape the sandbox and reach the real filesystem.
419 struct cmsghdr
* cmsg
;
420 msg
.msg_control
= control_buffer
;
421 msg
.msg_controllen
= sizeof(control_buffer
);
422 cmsg
= CMSG_FIRSTHDR(&msg
);
423 cmsg
->cmsg_level
= SOL_SOCKET
;
424 cmsg
->cmsg_type
= SCM_RIGHTS
;
425 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
426 memcpy(CMSG_DATA(cmsg
), &reply_fd
, sizeof(reply_fd
));
427 msg
.msg_controllen
= cmsg
->cmsg_len
;
430 if (HANDLE_EINTR(sendmsg(fds
[0]->get(), &msg
, MSG_DONTWAIT
)) < 0)
431 PLOG(ERROR
) << "sendmsg";
434 SandboxIPCHandler::~SandboxIPCHandler() {
436 if (blink_platform_impl_
)
437 blink::shutdownWithoutV8();
439 if (IGNORE_EINTR(close(lifeline_fd_
)) < 0)
440 PLOG(ERROR
) << "close";
441 if (IGNORE_EINTR(close(browser_socket_
)) < 0)
442 PLOG(ERROR
) << "close";
445 void SandboxIPCHandler::EnsureWebKitInitialized() {
446 if (blink_platform_impl_
)
448 blink_platform_impl_
.reset(new BlinkPlatformImpl
);
449 blink::initializeWithoutV8(blink_platform_impl_
.get());
452 } // namespace content