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];
135 base::UnixDomainSocket::RecvMsg(fd
, buf
, sizeof(buf
), &fds
);
137 // TODO: should send an error reply, or the sender might block forever.
138 NOTREACHED() << "Sandbox host message is larger than kMaxFontFamilyLength";
144 base::Pickle
pickle(buf
, len
);
145 base::PickleIterator
iter(pickle
);
148 if (!iter
.ReadInt(&kind
))
151 if (kind
== FontConfigIPC::METHOD_MATCH
) {
152 HandleFontMatchRequest(fd
, iter
, fds
.get());
153 } else if (kind
== FontConfigIPC::METHOD_OPEN
) {
154 HandleFontOpenRequest(fd
, iter
, fds
.get());
155 } else if (kind
== LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR
) {
156 HandleGetFallbackFontForChar(fd
, iter
, fds
.get());
157 } else if (kind
== LinuxSandbox::METHOD_LOCALTIME
) {
158 HandleLocaltime(fd
, iter
, fds
.get());
159 } else if (kind
== LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE
) {
160 HandleGetStyleForStrike(fd
, iter
, fds
.get());
161 } else if (kind
== LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT
) {
162 HandleMakeSharedMemorySegment(fd
, iter
, fds
.get());
163 } else if (kind
== LinuxSandbox::METHOD_MATCH_WITH_FALLBACK
) {
164 HandleMatchWithFallback(fd
, iter
, fds
.get());
168 int SandboxIPCHandler::FindOrAddPath(const SkString
& path
) {
169 int count
= paths_
.count();
170 for (int i
= 0; i
< count
; ++i
) {
171 if (path
== *paths_
[i
])
174 *paths_
.append() = new SkString(path
);
178 void SandboxIPCHandler::HandleFontMatchRequest(
180 base::PickleIterator iter
,
181 const std::vector
<base::ScopedFD
*>& fds
) {
182 uint32_t requested_style
;
184 if (!iter
.ReadString(&family
) || !iter
.ReadUInt32(&requested_style
))
187 SkFontConfigInterface::FontIdentity result_identity
;
188 SkString result_family
;
189 SkTypeface::Style result_style
;
190 SkFontConfigInterface
* fc
=
191 SkFontConfigInterface::GetSingletonDirectInterface();
193 fc
->matchFamilyName(family
.c_str(),
194 static_cast<SkTypeface::Style
>(requested_style
),
201 reply
.WriteBool(false);
203 // Stash away the returned path, so we can give it an ID (index)
204 // which will later be given to us in a request to open the file.
205 int index
= FindOrAddPath(result_identity
.fString
);
206 result_identity
.fID
= static_cast<uint32_t>(index
);
208 reply
.WriteBool(true);
209 skia::WriteSkString(&reply
, result_family
);
210 skia::WriteSkFontIdentity(&reply
, result_identity
);
211 reply
.WriteUInt32(result_style
);
213 SendRendererReply(fds
, reply
, -1);
216 void SandboxIPCHandler::HandleFontOpenRequest(
218 base::PickleIterator iter
,
219 const std::vector
<base::ScopedFD
*>& fds
) {
221 if (!iter
.ReadUInt32(&index
))
223 if (index
>= static_cast<uint32_t>(paths_
.count()))
225 const int result_fd
= open(paths_
[index
]->c_str(), O_RDONLY
);
228 if (result_fd
== -1) {
229 reply
.WriteBool(false);
231 reply
.WriteBool(true);
234 // The receiver will have its own access to the file, so we will close it
236 SendRendererReply(fds
, reply
, result_fd
);
238 if (result_fd
>= 0) {
239 int err
= IGNORE_EINTR(close(result_fd
));
244 void SandboxIPCHandler::HandleGetFallbackFontForChar(
246 base::PickleIterator iter
,
247 const std::vector
<base::ScopedFD
*>& fds
) {
248 // The other side of this call is
249 // content/common/child_process_sandbox_support_impl_linux.cc
251 EnsureWebKitInitialized();
253 if (!iter
.ReadInt(&c
))
256 std::string preferred_locale
;
257 if (!iter
.ReadString(&preferred_locale
))
260 blink::WebFallbackFont fallbackFont
;
261 WebFontInfo::fallbackFontForChar(c
, preferred_locale
.c_str(), &fallbackFont
);
263 int pathIndex
= FindOrAddPath(SkString(fallbackFont
.filename
.data()));
264 fallbackFont
.fontconfigInterfaceId
= pathIndex
;
267 if (fallbackFont
.name
.data()) {
268 reply
.WriteString(fallbackFont
.name
.data());
270 reply
.WriteString(std::string());
272 if (fallbackFont
.filename
.data()) {
273 reply
.WriteString(fallbackFont
.filename
.data());
275 reply
.WriteString(std::string());
277 reply
.WriteInt(fallbackFont
.fontconfigInterfaceId
);
278 reply
.WriteInt(fallbackFont
.ttcIndex
);
279 reply
.WriteBool(fallbackFont
.isBold
);
280 reply
.WriteBool(fallbackFont
.isItalic
);
281 SendRendererReply(fds
, reply
, -1);
284 void SandboxIPCHandler::HandleGetStyleForStrike(
286 base::PickleIterator iter
,
287 const std::vector
<base::ScopedFD
*>& fds
) {
292 if (!iter
.ReadString(&family
) ||
293 !iter
.ReadBool(&bold
) ||
294 !iter
.ReadBool(&italic
) ||
295 !iter
.ReadUInt16(&pixel_size
)) {
299 EnsureWebKitInitialized();
301 gfx::FontRenderParamsQuery query
;
302 query
.families
.push_back(family
);
303 query
.pixel_size
= pixel_size
;
304 query
.style
= gfx::Font::NORMAL
|
305 (bold
? gfx::Font::BOLD
: 0) | (italic
? gfx::Font::ITALIC
: 0);
306 const gfx::FontRenderParams params
= gfx::GetFontRenderParams(query
, NULL
);
308 // These are passed as ints since they're interpreted as tri-state chars in
311 reply
.WriteInt(params
.use_bitmaps
);
312 reply
.WriteInt(params
.autohinter
);
313 reply
.WriteInt(params
.hinting
!= gfx::FontRenderParams::HINTING_NONE
);
314 reply
.WriteInt(ConvertHinting(params
.hinting
));
315 reply
.WriteInt(params
.antialiasing
);
316 reply
.WriteInt(ConvertSubpixelRendering(params
.subpixel_rendering
));
317 reply
.WriteInt(params
.subpixel_positioning
);
319 SendRendererReply(fds
, reply
, -1);
322 void SandboxIPCHandler::HandleLocaltime(
324 base::PickleIterator iter
,
325 const std::vector
<base::ScopedFD
*>& fds
) {
326 // The other side of this call is in zygote_main_linux.cc
328 std::string time_string
;
329 if (!iter
.ReadString(&time_string
) || time_string
.size() != sizeof(time_t))
333 memcpy(&time
, time_string
.data(), sizeof(time
));
334 // We use localtime here because we need the tm_zone field to be filled
335 // out. Since we are a single-threaded process, this is safe.
336 const struct tm
* expanded_time
= localtime(&time
);
338 std::string result_string
;
339 const char* time_zone_string
= "";
340 if (expanded_time
!= NULL
) {
341 result_string
= std::string(reinterpret_cast<const char*>(expanded_time
),
343 time_zone_string
= expanded_time
->tm_zone
;
347 reply
.WriteString(result_string
);
348 reply
.WriteString(time_zone_string
);
349 SendRendererReply(fds
, reply
, -1);
352 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
354 base::PickleIterator iter
,
355 const std::vector
<base::ScopedFD
*>& fds
) {
356 base::SharedMemoryCreateOptions options
;
358 if (!iter
.ReadUInt32(&size
))
361 if (!iter
.ReadBool(&options
.executable
))
364 base::SharedMemory shm
;
365 if (shm
.Create(options
))
366 shm_fd
= shm
.handle().fd
;
368 SendRendererReply(fds
, reply
, shm_fd
);
371 void SandboxIPCHandler::HandleMatchWithFallback(
373 base::PickleIterator iter
,
374 const std::vector
<base::ScopedFD
*>& fds
) {
376 bool is_bold
, is_italic
;
377 uint32 charset
, fallback_family
;
379 if (!iter
.ReadString(&face
) || face
.empty() ||
380 !iter
.ReadBool(&is_bold
) ||
381 !iter
.ReadBool(&is_italic
) ||
382 !iter
.ReadUInt32(&charset
) ||
383 !iter
.ReadUInt32(&fallback_family
)) {
387 int font_fd
= MatchFontFaceWithFallback(
388 face
, is_bold
, is_italic
, charset
, fallback_family
);
391 SendRendererReply(fds
, reply
, font_fd
);
394 if (IGNORE_EINTR(close(font_fd
)) < 0)
395 PLOG(ERROR
) << "close";
399 void SandboxIPCHandler::SendRendererReply(
400 const std::vector
<base::ScopedFD
*>& fds
,
401 const base::Pickle
& reply
,
404 memset(&msg
, 0, sizeof(msg
));
405 struct iovec iov
= {const_cast<void*>(reply
.data()), reply
.size()};
409 char control_buffer
[CMSG_SPACE(sizeof(int))];
411 if (reply_fd
!= -1) {
413 if (fstat(reply_fd
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
414 LOG(FATAL
) << "Tried to send a directory descriptor over sandbox IPC";
415 // We must never send directory descriptors to a sandboxed process
416 // because they can use openat with ".." elements in the path in order
417 // to escape the sandbox and reach the real filesystem.
420 struct cmsghdr
* cmsg
;
421 msg
.msg_control
= control_buffer
;
422 msg
.msg_controllen
= sizeof(control_buffer
);
423 cmsg
= CMSG_FIRSTHDR(&msg
);
424 cmsg
->cmsg_level
= SOL_SOCKET
;
425 cmsg
->cmsg_type
= SCM_RIGHTS
;
426 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
427 memcpy(CMSG_DATA(cmsg
), &reply_fd
, sizeof(reply_fd
));
428 msg
.msg_controllen
= cmsg
->cmsg_len
;
431 if (HANDLE_EINTR(sendmsg(fds
[0]->get(), &msg
, MSG_DONTWAIT
)) < 0)
432 PLOG(ERROR
) << "sendmsg";
435 SandboxIPCHandler::~SandboxIPCHandler() {
437 if (blink_platform_impl_
)
438 blink::shutdownWithoutV8();
440 if (IGNORE_EINTR(close(lifeline_fd_
)) < 0)
441 PLOG(ERROR
) << "close";
442 if (IGNORE_EINTR(close(browser_socket_
)) < 0)
443 PLOG(ERROR
) << "close";
446 void SandboxIPCHandler::EnsureWebKitInitialized() {
447 if (blink_platform_impl_
)
449 blink_platform_impl_
.reset(new BlinkPlatformImpl
);
450 blink::initializeWithoutV8(blink_platform_impl_
.get());
453 } // namespace content