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) { | |
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; | |
Jiang Jiang
2014/08/13 10:48:08
This seems wrong as the original code is:
for (Fi
Nico
2014/08/13 15:43:17
Hm, that seems right. I guess noone uses the compo
| |
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 |