| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dlfcn.h> | 5 #include <dlfcn.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <pthread.h> | 7 #include <pthread.h> |
| 8 #include <stdio.h> | 8 #include <stdio.h> |
| 9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #include "content/common/font_config_ipc_linux.h" | 29 #include "content/common/font_config_ipc_linux.h" |
| 30 #include "content/common/pepper_plugin_registry.h" | 30 #include "content/common/pepper_plugin_registry.h" |
| 31 #include "content/common/sandbox_methods_linux.h" | 31 #include "content/common/sandbox_methods_linux.h" |
| 32 #include "content/common/seccomp_sandbox.h" | 32 #include "content/common/seccomp_sandbox.h" |
| 33 #include "content/common/zygote_commands_linux.h" | 33 #include "content/common/zygote_commands_linux.h" |
| 34 #include "content/public/common/content_switches.h" | 34 #include "content/public/common/content_switches.h" |
| 35 #include "content/public/common/main_function_params.h" | 35 #include "content/public/common/main_function_params.h" |
| 36 #include "content/public/common/sandbox_linux.h" | 36 #include "content/public/common/sandbox_linux.h" |
| 37 #include "content/public/common/zygote_fork_delegate_linux.h" | 37 #include "content/public/common/zygote_fork_delegate_linux.h" |
| 38 #include "content/zygote/zygote_linux.h" | 38 #include "content/zygote/zygote_linux.h" |
| 39 #include "sandbox/linux/services/libc_urandom_override.h" |
| 39 #include "skia/ext/SkFontHost_fontconfig_control.h" | 40 #include "skia/ext/SkFontHost_fontconfig_control.h" |
| 40 #include "unicode/timezone.h" | 41 #include "unicode/timezone.h" |
| 41 | 42 |
| 42 #if defined(OS_LINUX) | 43 #if defined(OS_LINUX) |
| 43 #include <sys/epoll.h> | 44 #include <sys/epoll.h> |
| 44 #include <sys/prctl.h> | 45 #include <sys/prctl.h> |
| 45 #include <sys/signal.h> | 46 #include <sys/signal.h> |
| 46 #else | 47 #else |
| 47 #include <signal.h> | 48 #include <signal.h> |
| 48 #endif | 49 #endif |
| 49 | 50 |
| 50 namespace content { | 51 namespace content { |
| 51 | 52 |
| 52 // See http://code.google.com/p/chromium/wiki/LinuxZygote | 53 // See http://code.google.com/p/chromium/wiki/LinuxZygote |
| 53 | 54 |
| 54 static const char kUrandomDevPath[] = "/dev/urandom"; | |
| 55 | |
| 56 // The SUID sandbox sets this environment variable to a file descriptor | 55 // The SUID sandbox sets this environment variable to a file descriptor |
| 57 // over which we can signal that we have completed our startup and can be | 56 // over which we can signal that we have completed our startup and can be |
| 58 // chrooted. | 57 // chrooted. |
| 59 static const char kSUIDSandboxVar[] = "SBX_D"; | 58 static const char kSUIDSandboxVar[] = "SBX_D"; |
| 60 | 59 |
| 61 // With SELinux we can carve out a precise sandbox, so we don't have to play | 60 // With SELinux we can carve out a precise sandbox, so we don't have to play |
| 62 // with intercepting libc calls. | 61 // with intercepting libc calls. |
| 63 #if !defined(CHROMIUM_SELINUX) | 62 #if !defined(CHROMIUM_SELINUX) |
| 64 | 63 |
| 65 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 64 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 // Our first attempt involved some assembly to patch the GOT of the current | 133 // Our first attempt involved some assembly to patch the GOT of the current |
| 135 // module. This worked, but was platform specific and doesn't catch the case | 134 // module. This worked, but was platform specific and doesn't catch the case |
| 136 // where a library makes a call rather than current module. | 135 // where a library makes a call rather than current module. |
| 137 // | 136 // |
| 138 // We also considered patching the function in place, but this would again by | 137 // We also considered patching the function in place, but this would again by |
| 139 // platform specific and the above technique seems to work well enough. | 138 // platform specific and the above technique seems to work well enough. |
| 140 | 139 |
| 141 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); | 140 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); |
| 142 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, | 141 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, |
| 143 struct tm* result); | 142 struct tm* result); |
| 144 typedef FILE* (*FopenFunction)(const char* path, const char* mode); | |
| 145 typedef int (*XstatFunction)(int version, const char *path, struct stat *buf); | |
| 146 typedef int (*Xstat64Function)(int version, const char *path, | |
| 147 struct stat64 *buf); | |
| 148 | 143 |
| 149 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; | 144 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; |
| 150 static LocaltimeFunction g_libc_localtime; | 145 static LocaltimeFunction g_libc_localtime; |
| 151 static LocaltimeFunction g_libc_localtime64; | 146 static LocaltimeFunction g_libc_localtime64; |
| 152 static LocaltimeRFunction g_libc_localtime_r; | 147 static LocaltimeRFunction g_libc_localtime_r; |
| 153 static LocaltimeRFunction g_libc_localtime64_r; | 148 static LocaltimeRFunction g_libc_localtime64_r; |
| 154 | 149 |
| 155 // http://crbug.com/123263, see below. | |
| 156 #if !defined(ADDRESS_SANITIZER) | |
| 157 static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT; | |
| 158 static FopenFunction g_libc_fopen; | |
| 159 static FopenFunction g_libc_fopen64; | |
| 160 static XstatFunction g_libc_xstat; | |
| 161 static Xstat64Function g_libc_xstat64; | |
| 162 #endif | |
| 163 | |
| 164 static void InitLibcLocaltimeFunctions() { | 150 static void InitLibcLocaltimeFunctions() { |
| 165 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( | 151 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( |
| 166 dlsym(RTLD_NEXT, "localtime")); | 152 dlsym(RTLD_NEXT, "localtime")); |
| 167 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( | 153 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( |
| 168 dlsym(RTLD_NEXT, "localtime64")); | 154 dlsym(RTLD_NEXT, "localtime64")); |
| 169 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( | 155 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( |
| 170 dlsym(RTLD_NEXT, "localtime_r")); | 156 dlsym(RTLD_NEXT, "localtime_r")); |
| 171 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( | 157 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( |
| 172 dlsym(RTLD_NEXT, "localtime64_r")); | 158 dlsym(RTLD_NEXT, "localtime64_r")); |
| 173 | 159 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 if (g_am_zygote_or_renderer) { | 245 if (g_am_zygote_or_renderer) { |
| 260 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); | 246 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); |
| 261 return result; | 247 return result; |
| 262 } else { | 248 } else { |
| 263 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, | 249 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, |
| 264 InitLibcLocaltimeFunctions)); | 250 InitLibcLocaltimeFunctions)); |
| 265 return g_libc_localtime64_r(timep, result); | 251 return g_libc_localtime64_r(timep, result); |
| 266 } | 252 } |
| 267 } | 253 } |
| 268 | 254 |
| 269 // TODO(sergeyu): Currently this code doesn't work properly under ASAN | |
| 270 // - it crashes content_unittests. Make sure it works properly and | |
| 271 // enable it here. http://crbug.com/123263 | |
| 272 #if !defined(ADDRESS_SANITIZER) | |
| 273 | |
| 274 static void InitLibcFileIOFunctions() { | |
| 275 g_libc_fopen = reinterpret_cast<FopenFunction>( | |
| 276 dlsym(RTLD_NEXT, "fopen")); | |
| 277 g_libc_fopen64 = reinterpret_cast<FopenFunction>( | |
| 278 dlsym(RTLD_NEXT, "fopen64")); | |
| 279 | |
| 280 if (!g_libc_fopen) { | |
| 281 LOG(FATAL) << "Failed to get fopen() from libc."; | |
| 282 } else if (!g_libc_fopen64) { | |
| 283 #if !defined(OS_OPENBSD) && !defined(OS_FREEBSD) | |
| 284 LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead."; | |
| 285 #endif // !defined(OS_OPENBSD) && !defined(OS_FREEBSD) | |
| 286 g_libc_fopen64 = g_libc_fopen; | |
| 287 } | |
| 288 | |
| 289 // TODO(sergeyu): This works only on systems with glibc. Fix it to | |
| 290 // work properly on other systems if necessary. | |
| 291 g_libc_xstat = reinterpret_cast<XstatFunction>( | |
| 292 dlsym(RTLD_NEXT, "__xstat")); | |
| 293 g_libc_xstat64 = reinterpret_cast<Xstat64Function>( | |
| 294 dlsym(RTLD_NEXT, "__xstat64")); | |
| 295 | |
| 296 if (!g_libc_xstat) { | |
| 297 LOG(FATAL) << "Failed to get __xstat() from libc."; | |
| 298 } | |
| 299 if (!g_libc_xstat64) { | |
| 300 LOG(WARNING) << "Failed to get __xstat64() from libc."; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 // fopen() and fopen64() are intercepted here so that NSS can open | |
| 305 // /dev/urandom to seed its random number generator. NSS is used by | |
| 306 // remoting in the sendbox. | |
| 307 | |
| 308 // fopen() call may be redirected to fopen64() in stdio.h using | |
| 309 // __REDIRECT(), which sets asm name for fopen() to "fopen64". This | |
| 310 // means that we cannot override fopen() directly here. Instead the | |
| 311 // the code below defines fopen_override() function with asm name | |
| 312 // "fopen", so that all references to fopen() will resolve to this | |
| 313 // function. | |
| 314 __attribute__ ((__visibility__("default"))) | |
| 315 FILE* fopen_override(const char* path, const char* mode) __asm__ ("fopen"); | |
| 316 | |
| 317 __attribute__ ((__visibility__("default"))) | |
| 318 FILE* fopen_override(const char* path, const char* mode) { | |
| 319 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
| 320 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); | |
| 321 if (fd < 0) { | |
| 322 PLOG(ERROR) << "dup() failed."; | |
| 323 return NULL; | |
| 324 } | |
| 325 return fdopen(fd, mode); | |
| 326 } else { | |
| 327 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
| 328 InitLibcFileIOFunctions)); | |
| 329 return g_libc_fopen(path, mode); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 __attribute__ ((__visibility__("default"))) | |
| 334 FILE* fopen64(const char* path, const char* mode) { | |
| 335 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
| 336 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); | |
| 337 if (fd < 0) { | |
| 338 PLOG(ERROR) << "dup() failed."; | |
| 339 return NULL; | |
| 340 } | |
| 341 return fdopen(fd, mode); | |
| 342 } else { | |
| 343 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
| 344 InitLibcFileIOFunctions)); | |
| 345 return g_libc_fopen64(path, mode); | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 // stat() is subject to the same problem as fopen(), so we have to use | |
| 350 // the same trick to override it. | |
| 351 __attribute__ ((__visibility__("default"))) | |
| 352 int xstat_override(int version, | |
| 353 const char *path, | |
| 354 struct stat *buf) __asm__ ("__xstat"); | |
| 355 | |
| 356 __attribute__ ((__visibility__("default"))) | |
| 357 int xstat_override(int version, const char *path, struct stat *buf) { | |
| 358 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
| 359 int result = __fxstat(version, base::GetUrandomFD(), buf); | |
| 360 return result; | |
| 361 } else { | |
| 362 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
| 363 InitLibcFileIOFunctions)); | |
| 364 return g_libc_xstat(version, path, buf); | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 __attribute__ ((__visibility__("default"))) | |
| 369 int xstat64_override(int version, | |
| 370 const char *path, | |
| 371 struct stat64 *buf) __asm__ ("__xstat64"); | |
| 372 | |
| 373 __attribute__ ((__visibility__("default"))) | |
| 374 int xstat64_override(int version, const char *path, struct stat64 *buf) { | |
| 375 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
| 376 int result = __fxstat64(version, base::GetUrandomFD(), buf); | |
| 377 return result; | |
| 378 } else { | |
| 379 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
| 380 InitLibcFileIOFunctions)); | |
| 381 CHECK(g_libc_xstat64); | |
| 382 return g_libc_xstat64(version, path, buf); | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 #endif // !ADDRESS_SANITIZER | |
| 387 | |
| 388 #endif // !CHROMIUM_SELINUX | 255 #endif // !CHROMIUM_SELINUX |
| 389 | 256 |
| 390 // This function triggers the static and lazy construction of objects that need | 257 // This function triggers the static and lazy construction of objects that need |
| 391 // to be created before imposing the sandbox. | 258 // to be created before imposing the sandbox. |
| 392 static void PreSandboxInit() { | 259 static void PreSandboxInit() { |
| 393 base::RandUint64(); | 260 base::RandUint64(); |
| 394 | 261 |
| 395 base::SysInfo::MaxSharedMemorySize(); | 262 base::SysInfo::MaxSharedMemorySize(); |
| 396 | 263 |
| 397 // ICU DateFormat class (used in base/time_format.cc) needs to get the | 264 // ICU DateFormat class (used in base/time_format.cc) needs to get the |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 new FontConfigIPC(Zygote::kMagicSandboxIPCDescriptor)); | 482 new FontConfigIPC(Zygote::kMagicSandboxIPCDescriptor)); |
| 616 return true; | 483 return true; |
| 617 } | 484 } |
| 618 | 485 |
| 619 #endif // CHROMIUM_SELINUX | 486 #endif // CHROMIUM_SELINUX |
| 620 | 487 |
| 621 bool ZygoteMain(const MainFunctionParams& params, | 488 bool ZygoteMain(const MainFunctionParams& params, |
| 622 ZygoteForkDelegate* forkdelegate) { | 489 ZygoteForkDelegate* forkdelegate) { |
| 623 #if !defined(CHROMIUM_SELINUX) | 490 #if !defined(CHROMIUM_SELINUX) |
| 624 g_am_zygote_or_renderer = true; | 491 g_am_zygote_or_renderer = true; |
| 492 sandbox::InitLibcUrandomOverrides(); |
| 625 #endif | 493 #endif |
| 626 | 494 |
| 627 int proc_fd_for_seccomp = -1; | 495 int proc_fd_for_seccomp = -1; |
| 628 #if defined(SECCOMP_SANDBOX) | 496 #if defined(SECCOMP_SANDBOX) |
| 629 if (SeccompSandboxEnabled()) { | 497 if (SeccompSandboxEnabled()) { |
| 630 // The seccomp sandbox needs access to files in /proc, which might be denied | 498 // The seccomp sandbox needs access to files in /proc, which might be denied |
| 631 // after one of the other sandboxes have been started. So, obtain a suitable | 499 // after one of the other sandboxes have been started. So, obtain a suitable |
| 632 // file handle in advance. | 500 // file handle in advance. |
| 633 proc_fd_for_seccomp = open("/proc", O_DIRECTORY | O_RDONLY); | 501 proc_fd_for_seccomp = open("/proc", O_DIRECTORY | O_RDONLY); |
| 634 if (proc_fd_for_seccomp < 0) { | 502 if (proc_fd_for_seccomp < 0) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 } | 560 } |
| 693 } | 561 } |
| 694 #endif // SECCOMP_SANDBOX | 562 #endif // SECCOMP_SANDBOX |
| 695 | 563 |
| 696 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); | 564 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); |
| 697 // This function call can return multiple times, once per fork(). | 565 // This function call can return multiple times, once per fork(). |
| 698 return zygote.ProcessRequests(); | 566 return zygote.ProcessRequests(); |
| 699 } | 567 } |
| 700 | 568 |
| 701 } // namespace content | 569 } // namespace content |
| OLD | NEW |