Chromium Code Reviews| 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 "content/common/sandbox_mac.h" | 5 #include "content/common/sandbox_mac.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 extern "C" { | 9 extern "C" { |
| 10 #include <sandbox.h> | 10 #include <sandbox.h> |
| 11 } | 11 } |
| 12 #include <signal.h> | 12 #include <signal.h> |
| 13 #include <sys/param.h> | 13 #include <sys/param.h> |
| 14 | 14 |
| 15 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
| 18 #include "base/file_util.h" | 18 #include "base/file_util.h" |
| 19 #include "base/mac/bundle_locations.h" | |
| 19 #include "base/mac/mac_util.h" | 20 #include "base/mac/mac_util.h" |
| 20 #include "base/mac/scoped_cftyperef.h" | 21 #include "base/mac/scoped_cftyperef.h" |
| 21 #include "base/mac/scoped_nsautorelease_pool.h" | 22 #include "base/mac/scoped_nsautorelease_pool.h" |
| 22 #include "base/memory/scoped_nsobject.h" | 23 #include "base/memory/scoped_nsobject.h" |
| 23 #include "base/rand_util.h" | 24 #include "base/rand_util.h" |
| 24 #include "base/string16.h" | 25 #include "base/string16.h" |
| 25 #include "base/string_piece.h" | 26 #include "base/string_piece.h" |
| 26 #include "base/string_util.h" | 27 #include "base/string_util.h" |
| 27 #include "base/stringprintf.h" | 28 #include "base/stringprintf.h" |
| 28 #include "base/sys_info.h" | 29 #include "base/sys_info.h" |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 // Copy bad string to the stack so it's recorded in the crash dump. | 99 // Copy bad string to the stack so it's recorded in the crash dump. |
| 99 char bad_string[256] = {0}; | 100 char bad_string[256] = {0}; |
| 100 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); | 101 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); |
| 101 DLOG(FATAL) << "String quoting failed " << bad_string; | 102 DLOG(FATAL) << "String quoting failed " << bad_string; |
| 102 } | 103 } |
| 103 | 104 |
| 104 } // namespace | 105 } // namespace |
| 105 | 106 |
| 106 namespace sandbox { | 107 namespace sandbox { |
| 107 | 108 |
| 109 // static | |
| 110 NSString* Sandbox::AllowMetadataForPath(const FilePath& allowed_path) { | |
|
Nico
2012/06/05 17:54:21
This was extracted almost unchanged from below. (I
| |
| 111 // Collect a list of all parent directories. | |
| 112 FilePath last_path = allowed_path; | |
| 113 std::vector<FilePath> subpaths; | |
| 114 for (FilePath path = allowed_path; | |
|
Nico
2012/06/05 17:54:21
Note that this now starts at |allowed_path|, not a
| |
| 115 path.value() != last_path.value(); | |
| 116 path = path.DirName()) { | |
| 117 subpaths.push_back(path); | |
| 118 last_path = path; | |
| 119 } | |
| 120 | |
| 121 // Iterate through all parents and allow stat() on them explicitly. | |
| 122 NSString* sandbox_command = @"(allow file-read-metadata "; | |
| 123 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); | |
| 124 i != subpaths.rend(); | |
| 125 ++i) { | |
| 126 std::string subdir_escaped; | |
| 127 if (!QuotePlainString(i->value(), &subdir_escaped)) { | |
| 128 FatalStringQuoteException(i->value()); | |
| 129 return nil; | |
| 130 } | |
| 131 | |
| 132 NSString* subdir_escaped_ns = | |
| 133 base::SysUTF8ToNSString(subdir_escaped.c_str()); | |
| 134 sandbox_command = | |
| 135 [sandbox_command stringByAppendingFormat:@"(literal \"%@\")", | |
| 136 subdir_escaped_ns]; | |
| 137 } | |
| 138 | |
| 139 return [sandbox_command stringByAppendingString:@")"]; | |
| 140 } | |
| 108 | 141 |
| 109 // static | 142 // static |
| 110 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { | 143 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { |
| 111 dst->clear(); | 144 dst->clear(); |
| 112 | 145 |
| 113 const char* src = src_utf8.c_str(); | 146 const char* src = src_utf8.c_str(); |
| 114 int32_t length = src_utf8.length(); | 147 int32_t length = src_utf8.length(); |
| 115 int32_t position = 0; | 148 int32_t position = 0; |
| 116 while (position < length) { | 149 while (position < length) { |
| 117 UChar32 c; | 150 UChar32 c; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 // The extension code in Chrome calls realpath() which fails if it can't call | 320 // The extension code in Chrome calls realpath() which fails if it can't call |
| 288 // stat() on one of the parent directories in the path. | 321 // stat() on one of the parent directories in the path. |
| 289 // The solution to this is to allow statting the parent directories themselves | 322 // The solution to this is to allow statting the parent directories themselves |
| 290 // but not their contents. We need to add a separate rule for each parent | 323 // but not their contents. We need to add a separate rule for each parent |
| 291 // directory. | 324 // directory. |
| 292 | 325 |
| 293 // The sandbox only understands "real" paths. This resolving step is | 326 // The sandbox only understands "real" paths. This resolving step is |
| 294 // needed so the caller doesn't need to worry about things like /var | 327 // needed so the caller doesn't need to worry about things like /var |
| 295 // being a link to /private/var (like in the paths CreateNewTempDirectory() | 328 // being a link to /private/var (like in the paths CreateNewTempDirectory() |
| 296 // returns). | 329 // returns). |
| 297 FilePath allowed_dir_canonical(allowed_dir); | 330 FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
| 298 GetCanonicalSandboxPath(&allowed_dir_canonical); | |
| 299 | 331 |
| 300 // Collect a list of all parent directories. | 332 NSString* sandbox_command = AllowMetadataForPath(allowed_dir_canonical); |
| 301 FilePath last_path = allowed_dir_canonical; | 333 sandbox_command = [sandbox_command |
| 302 std::vector<FilePath> subpaths; | 334 substringToIndex:[sandbox_command length] - 1]; // strip trailing ')' |
| 303 for (FilePath path = allowed_dir_canonical.DirName(); | |
| 304 path.value() != last_path.value(); | |
| 305 path = path.DirName()) { | |
| 306 subpaths.push_back(path); | |
| 307 last_path = path; | |
| 308 } | |
| 309 | |
| 310 // Iterate through all parents and allow stat() on them explicitly. | |
| 311 NSString* sandbox_command = @"(allow file-read-metadata "; | |
| 312 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); | |
| 313 i != subpaths.rend(); | |
| 314 ++i) { | |
| 315 std::string subdir_escaped; | |
| 316 if (!QuotePlainString(i->value(), &subdir_escaped)) { | |
| 317 FatalStringQuoteException(i->value()); | |
| 318 return nil; | |
| 319 } | |
| 320 | |
| 321 NSString* subdir_escaped_ns = | |
| 322 base::SysUTF8ToNSString(subdir_escaped.c_str()); | |
| 323 sandbox_command = | |
| 324 [sandbox_command stringByAppendingFormat:@"(literal \"%@\")", | |
| 325 subdir_escaped_ns]; | |
| 326 } | |
| 327 | 335 |
| 328 // Finally append the leaf directory. Unlike its parents (for which only | 336 // Finally append the leaf directory. Unlike its parents (for which only |
| 329 // stat() should be allowed), the leaf directory needs full access. | 337 // stat() should be allowed), the leaf directory needs full access. |
| 330 (*substitutions)["ALLOWED_DIR"] = | 338 (*substitutions)["ALLOWED_DIR"] = |
| 331 SandboxSubstring(allowed_dir_canonical.value(), | 339 SandboxSubstring(allowed_dir_canonical.value(), |
| 332 SandboxSubstring::REGEX); | 340 SandboxSubstring::REGEX); |
| 333 sandbox_command = | 341 sandbox_command = |
| 334 [sandbox_command | 342 [sandbox_command |
| 335 stringByAppendingString:@") (allow file-read* file-write*" | 343 stringByAppendingString:@") (allow file-read* file-write*" |
| 336 " (regex #\"@ALLOWED_DIR@\") )"]; | 344 " (regex #\"@ALLOWED_DIR@\") )"]; |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = | 525 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = |
| 518 SandboxSubstring("(with no-log)"); | 526 SandboxSubstring("(with no-log)"); |
| 519 } else { | 527 } else { |
| 520 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = SandboxSubstring(""); | 528 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = SandboxSubstring(""); |
| 521 } | 529 } |
| 522 | 530 |
| 523 // Splice the path of the user's home directory into the sandbox profile | 531 // Splice the path of the user's home directory into the sandbox profile |
| 524 // (see renderer.sb for details). | 532 // (see renderer.sb for details). |
| 525 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; | 533 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; |
| 526 | 534 |
| 527 FilePath home_dir_canonical(home_dir); | 535 FilePath home_dir_canonical = GetCanonicalSandboxPath(FilePath(home_dir)); |
| 528 GetCanonicalSandboxPath(&home_dir_canonical); | |
| 529 | 536 |
| 530 substitutions["USER_HOMEDIR_AS_LITERAL"] = | 537 substitutions["USER_HOMEDIR_AS_LITERAL"] = |
| 531 SandboxSubstring(home_dir_canonical.value(), | 538 SandboxSubstring(home_dir_canonical.value(), |
| 532 SandboxSubstring::LITERAL); | 539 SandboxSubstring::LITERAL); |
| 533 | 540 |
| 534 if (lion_or_later) { | 541 if (lion_or_later) { |
| 535 // >=10.7 Sandbox rules. | 542 // >=10.7 Sandbox rules. |
| 536 [tokens_to_remove addObject:@";10.7_OR_ABOVE"]; | 543 [tokens_to_remove addObject:@";10.7_OR_ABOVE"]; |
| 537 } | 544 } |
| 538 | 545 |
| 539 if (snow_leopard_or_later) { | 546 if (snow_leopard_or_later) { |
| 540 // >=10.6 Sandbox rules. | 547 // >=10.6 Sandbox rules. |
| 541 [tokens_to_remove addObject:@";10.6_OR_ABOVE"]; | 548 [tokens_to_remove addObject:@";10.6_OR_ABOVE"]; |
| 542 } else { | 549 } else { |
| 543 // Sandbox rules only for versions before 10.6. | 550 // Sandbox rules only for versions before 10.6. |
| 544 [tokens_to_remove addObject:@";BEFORE_10.6"]; | 551 [tokens_to_remove addObject:@";BEFORE_10.6"]; |
| 545 } | 552 } |
| 546 | 553 |
| 547 substitutions["COMPONENT_BUILD_WORKAROUND"] = SandboxSubstring(""); | 554 substitutions["COMPONENT_BUILD_WORKAROUND"] = SandboxSubstring(""); |
| 548 #if defined(COMPONENT_BUILD) | 555 #if defined(COMPONENT_BUILD) |
| 549 // dlopen() fails without file-read-metadata access if the executable image | 556 // dlopen() fails without file-read-metadata access if the executable image |
| 550 // contains LC_RPATH load commands. The components build uses those. | 557 // contains LC_RPATH load commands. The components build uses those. |
| 551 // See http://crbug.com/127465 | 558 // See http://crbug.com/127465 |
| 552 if (base::mac::IsOSSnowLeopardOrEarlier()) { | 559 if (base::mac::IsOSSnowLeopardOrEarlier()) { |
| 560 FilePath bundle_executable = base::mac::NSStringToFilePath( | |
| 561 [base::mac::MainBundle() executablePath]); | |
| 562 NSString* sandbox_command = AllowMetadataForPath( | |
| 563 GetCanonicalSandboxPath(bundle_executable)); | |
| 553 substitutions["COMPONENT_BUILD_WORKAROUND"] = | 564 substitutions["COMPONENT_BUILD_WORKAROUND"] = |
| 554 SandboxSubstring("(allow file-read-metadata)"); | 565 SandboxSubstring(base::SysNSStringToUTF8(sandbox_command)); |
| 555 } | 566 } |
| 556 #endif | 567 #endif |
| 557 | 568 |
| 558 // All information needed to assemble the final profile has been collected. | 569 // All information needed to assemble the final profile has been collected. |
| 559 // Merge it all together. | 570 // Merge it all together. |
| 560 std::string final_sandbox_profile_str; | 571 std::string final_sandbox_profile_str; |
| 561 if (!PostProcessSandboxProfile(sandbox_data, tokens_to_remove, substitutions, | 572 if (!PostProcessSandboxProfile(sandbox_data, tokens_to_remove, substitutions, |
| 562 &final_sandbox_profile_str)) { | 573 &final_sandbox_profile_str)) { |
| 563 return false; | 574 return false; |
| 564 } | 575 } |
| 565 | 576 |
| 566 // Initialize sandbox. | 577 // Initialize sandbox. |
| 567 char* error_buff = NULL; | 578 char* error_buff = NULL; |
| 568 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); | 579 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); |
| 569 bool success = (error == 0 && error_buff == NULL); | 580 bool success = (error == 0 && error_buff == NULL); |
| 570 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " | 581 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " |
| 571 << error | 582 << error |
| 572 << " " | 583 << " " |
| 573 << error_buff; | 584 << error_buff; |
| 574 sandbox_free_error(error_buff); | 585 sandbox_free_error(error_buff); |
| 575 return success; | 586 return success; |
| 576 } | 587 } |
| 577 | 588 |
| 578 // static | 589 // static |
| 579 void Sandbox::GetCanonicalSandboxPath(FilePath* path) { | 590 FilePath Sandbox::GetCanonicalSandboxPath(const FilePath& path) { |
| 580 int fd = HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)); | 591 int fd = HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)); |
| 581 if (fd < 0) { | 592 if (fd < 0) { |
| 582 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 593 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
| 583 << path->value(); | 594 << path.value(); |
| 584 return; | 595 return path; |
| 585 } | 596 } |
| 586 file_util::ScopedFD file_closer(&fd); | 597 file_util::ScopedFD file_closer(&fd); |
| 587 | 598 |
| 588 FilePath::CharType canonical_path[MAXPATHLEN]; | 599 FilePath::CharType canonical_path[MAXPATHLEN]; |
| 589 if (HANDLE_EINTR(fcntl(fd, F_GETPATH, canonical_path)) != 0) { | 600 if (HANDLE_EINTR(fcntl(fd, F_GETPATH, canonical_path)) != 0) { |
| 590 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 601 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
| 591 << path->value(); | 602 << path.value(); |
| 592 return; | 603 return path; |
| 593 } | 604 } |
| 594 | 605 |
| 595 *path = FilePath(canonical_path); | 606 return FilePath(canonical_path); |
| 596 } | 607 } |
| 597 | 608 |
| 598 } // namespace sandbox | 609 } // namespace sandbox |
| OLD | NEW |