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 #include <CoreFoundation/CFTimeZone.h> | 9 #include <CoreFoundation/CFTimeZone.h> |
10 extern "C" { | 10 extern "C" { |
(...skipping 25 matching lines...) Expand all Loading... |
36 #include "content/grit/content_resources.h" | 36 #include "content/grit/content_resources.h" |
37 #include "content/public/common/content_client.h" | 37 #include "content/public/common/content_client.h" |
38 #include "content/public/common/content_switches.h" | 38 #include "content/public/common/content_switches.h" |
39 #include "third_party/icu/source/common/unicode/uchar.h" | 39 #include "third_party/icu/source/common/unicode/uchar.h" |
40 #include "ui/base/layout.h" | 40 #include "ui/base/layout.h" |
41 #include "ui/gl/gl_surface.h" | 41 #include "ui/gl/gl_surface.h" |
42 | 42 |
43 extern "C" { | 43 extern "C" { |
44 void CGSSetDenyWindowServerConnections(bool); | 44 void CGSSetDenyWindowServerConnections(bool); |
45 void CGSShutdownServerConnections(); | 45 void CGSShutdownServerConnections(); |
46 | |
47 void* sandbox_create_params(); | |
48 int sandbox_set_param(void* params, const char* key, const char* value); | |
49 void* sandbox_compile_string(const char* profile_str, | |
50 void* params, | |
51 char** error); | |
52 int sandbox_apply(void* profile); | |
53 void sandbox_free_params(void* params); | |
54 void sandbox_free_profile(void* profile); | |
55 }; | 46 }; |
56 | 47 |
57 namespace content { | 48 namespace content { |
58 namespace { | 49 namespace { |
59 | 50 |
60 // Is the sandbox currently active. | 51 // Is the sandbox currently active. |
61 bool gSandboxIsActive = false; | 52 bool gSandboxIsActive = false; |
62 | 53 |
63 struct SandboxTypeToResourceIDMapping { | 54 struct SandboxTypeToResourceIDMapping { |
64 SandboxType sandbox_type; | 55 SandboxType sandbox_type; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 // in a central place. | 109 // in a central place. |
119 NOINLINE void FatalStringQuoteException(const std::string& str) { | 110 NOINLINE void FatalStringQuoteException(const std::string& str) { |
120 // Copy bad string to the stack so it's recorded in the crash dump. | 111 // Copy bad string to the stack so it's recorded in the crash dump. |
121 char bad_string[256] = {0}; | 112 char bad_string[256] = {0}; |
122 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); | 113 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); |
123 DLOG(FATAL) << "String quoting failed " << bad_string; | 114 DLOG(FATAL) << "String quoting failed " << bad_string; |
124 } | 115 } |
125 | 116 |
126 } // namespace | 117 } // namespace |
127 | 118 |
128 SandboxCompiler::SandboxCompiler(const std::string& profile_str) | 119 // static |
129 : params_map_(), profile_str_(profile_str) { | 120 NSString* Sandbox::AllowMetadataForPath(const base::FilePath& allowed_path) { |
130 } | 121 // Collect a list of all parent directories. |
131 | 122 base::FilePath last_path = allowed_path; |
132 SandboxCompiler::~SandboxCompiler() { | 123 std::vector<base::FilePath> subpaths; |
133 } | 124 for (base::FilePath path = allowed_path; |
134 | 125 path.value() != last_path.value(); |
135 bool SandboxCompiler::InsertBooleanParam(const std::string& key, bool value) { | 126 path = path.DirName()) { |
136 return params_map_.insert(std::make_pair(key, value ? "TRUE" : "FALSE")) | 127 subpaths.push_back(path); |
137 .second; | 128 last_path = path; |
138 } | |
139 | |
140 bool SandboxCompiler::InsertStringParam(const std::string& key, | |
141 const std::string& value) { | |
142 return params_map_.insert(std::make_pair(key, value)).second; | |
143 } | |
144 | |
145 void SandboxCompiler::FreeSandboxResources(void* profile, | |
146 void* params, | |
147 char* error) { | |
148 if (error) | |
149 sandbox_free_error(error); | |
150 if (params) | |
151 sandbox_free_params(params); | |
152 if (profile) | |
153 sandbox_free_profile(profile); | |
154 } | |
155 | |
156 bool SandboxCompiler::CompileAndApplyProfile(std::string* error) { | |
157 char* error_internal = nullptr; | |
158 void* profile = nullptr; | |
159 void* params = nullptr; | |
160 | |
161 if (!params_map_.empty()) { | |
162 params = sandbox_create_params(); | |
163 if (!params) | |
164 return false; | |
165 | |
166 for (const auto& kv : params_map_) | |
167 sandbox_set_param(params, kv.first.c_str(), kv.second.c_str()); | |
168 } | 129 } |
169 | 130 |
170 profile = | 131 // Iterate through all parents and allow stat() on them explicitly. |
171 sandbox_compile_string(profile_str_.c_str(), params, &error_internal); | 132 NSString* sandbox_command = @"(allow file-read-metadata "; |
172 if (!profile) { | 133 for (std::vector<base::FilePath>::reverse_iterator i = subpaths.rbegin(); |
173 error->assign(error_internal); | 134 i != subpaths.rend(); |
174 FreeSandboxResources(profile, params, error_internal); | 135 ++i) { |
175 return false; | 136 std::string subdir_escaped; |
| 137 if (!QuotePlainString(i->value(), &subdir_escaped)) { |
| 138 FatalStringQuoteException(i->value()); |
| 139 return nil; |
| 140 } |
| 141 |
| 142 NSString* subdir_escaped_ns = |
| 143 base::SysUTF8ToNSString(subdir_escaped.c_str()); |
| 144 sandbox_command = |
| 145 [sandbox_command stringByAppendingFormat:@"(literal \"%@\")", |
| 146 subdir_escaped_ns]; |
176 } | 147 } |
177 | 148 |
178 int result = sandbox_apply(profile); | 149 return [sandbox_command stringByAppendingString:@")"]; |
179 FreeSandboxResources(profile, params, error_internal); | |
180 return result == 0; | |
181 } | 150 } |
182 | 151 |
183 // static | 152 // static |
184 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { | 153 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { |
185 dst->clear(); | 154 dst->clear(); |
186 | 155 |
187 const char* src = src_utf8.c_str(); | 156 const char* src = src_utf8.c_str(); |
188 int32_t length = src_utf8.length(); | 157 int32_t length = src_utf8.length(); |
189 int32_t position = 0; | 158 int32_t position = 0; |
190 while (position < length) { | 159 while (position < length) { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 // Shutting down the connection requires connecting to WindowServer, | 342 // Shutting down the connection requires connecting to WindowServer, |
374 // so do this before actually engaging the sandbox. This is only done on | 343 // so do this before actually engaging the sandbox. This is only done on |
375 // 10.8 and higher because doing it on earlier OSes causes layout tests to | 344 // 10.8 and higher because doing it on earlier OSes causes layout tests to |
376 // fail <http://crbug.com/397642#c48>. This may cause two log messages to | 345 // fail <http://crbug.com/397642#c48>. This may cause two log messages to |
377 // be printed to the system logger on certain OS versions. | 346 // be printed to the system logger on certain OS versions. |
378 CGSSetDenyWindowServerConnections(true); | 347 CGSSetDenyWindowServerConnections(true); |
379 CGSShutdownServerConnections(); | 348 CGSShutdownServerConnections(); |
380 } | 349 } |
381 } | 350 } |
382 | 351 |
| 352 // static |
| 353 NSString* Sandbox::BuildAllowDirectoryAccessSandboxString( |
| 354 const base::FilePath& allowed_dir, |
| 355 SandboxVariableSubstitions* substitutions) { |
| 356 // A whitelist is used to determine which directories can be statted |
| 357 // This means that in the case of an /a/b/c/d/ directory, we may be able to |
| 358 // stat the leaf directory, but not its parent. |
| 359 // The extension code in Chrome calls realpath() which fails if it can't call |
| 360 // stat() on one of the parent directories in the path. |
| 361 // The solution to this is to allow statting the parent directories themselves |
| 362 // but not their contents. We need to add a separate rule for each parent |
| 363 // directory. |
| 364 |
| 365 // The sandbox only understands "real" paths. This resolving step is |
| 366 // needed so the caller doesn't need to worry about things like /var |
| 367 // being a link to /private/var (like in the paths CreateNewTempDirectory() |
| 368 // returns). |
| 369 base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
| 370 |
| 371 NSString* sandbox_command = AllowMetadataForPath(allowed_dir_canonical); |
| 372 sandbox_command = [sandbox_command |
| 373 substringToIndex:[sandbox_command length] - 1]; // strip trailing ')' |
| 374 |
| 375 // Finally append the leaf directory. Unlike its parents (for which only |
| 376 // stat() should be allowed), the leaf directory needs full access. |
| 377 (*substitutions)["ALLOWED_DIR"] = |
| 378 SandboxSubstring(allowed_dir_canonical.value(), |
| 379 SandboxSubstring::REGEX); |
| 380 sandbox_command = |
| 381 [sandbox_command |
| 382 stringByAppendingString:@") (allow file-read* file-write*" |
| 383 " (regex #\"@ALLOWED_DIR@\") )"]; |
| 384 return sandbox_command; |
| 385 } |
| 386 |
383 // Load the appropriate template for the given sandbox type. | 387 // Load the appropriate template for the given sandbox type. |
384 // Returns the template as an NSString or nil on error. | 388 // Returns the template as an NSString or nil on error. |
385 NSString* LoadSandboxTemplate(int sandbox_type) { | 389 NSString* LoadSandboxTemplate(int sandbox_type) { |
386 // We use a custom sandbox definition to lock things down as tightly as | 390 // We use a custom sandbox definition to lock things down as tightly as |
387 // possible. | 391 // possible. |
388 int sandbox_profile_resource_id = -1; | 392 int sandbox_profile_resource_id = -1; |
389 | 393 |
390 // Find resource id for sandbox profile to use for the specific sandbox type. | 394 // Find resource id for sandbox profile to use for the specific sandbox type. |
391 for (size_t i = 0; | 395 for (size_t i = 0; |
392 i < arraysize(kDefaultSandboxTypeToResourceIDMapping); | 396 i < arraysize(kDefaultSandboxTypeToResourceIDMapping); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 | 434 |
431 base::scoped_nsobject<NSString> sandbox_data( | 435 base::scoped_nsobject<NSString> sandbox_data( |
432 [[NSString alloc] initWithBytes:sandbox_definition.data() | 436 [[NSString alloc] initWithBytes:sandbox_definition.data() |
433 length:sandbox_definition.length() | 437 length:sandbox_definition.length() |
434 encoding:NSUTF8StringEncoding]); | 438 encoding:NSUTF8StringEncoding]); |
435 | 439 |
436 // Prefix sandbox_data with common_sandbox_prefix_data. | 440 // Prefix sandbox_data with common_sandbox_prefix_data. |
437 return [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; | 441 return [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; |
438 } | 442 } |
439 | 443 |
| 444 // static |
| 445 bool Sandbox::PostProcessSandboxProfile( |
| 446 NSString* sandbox_template, |
| 447 NSArray* comments_to_remove, |
| 448 SandboxVariableSubstitions& substitutions, |
| 449 std::string *final_sandbox_profile_str) { |
| 450 NSString* sandbox_data = [[sandbox_template copy] autorelease]; |
| 451 |
| 452 // Remove comments, e.g. ;10.7_OR_ABOVE . |
| 453 for (NSString* to_remove in comments_to_remove) { |
| 454 sandbox_data = [sandbox_data stringByReplacingOccurrencesOfString:to_remove |
| 455 withString:@""]; |
| 456 } |
| 457 |
| 458 // Split string on "@" characters. |
| 459 std::vector<std::string> raw_sandbox_pieces; |
| 460 if (Tokenize([sandbox_data UTF8String], "@", &raw_sandbox_pieces) == 0) { |
| 461 DLOG(FATAL) << "Bad Sandbox profile, should contain at least one token (" |
| 462 << [sandbox_data UTF8String] |
| 463 << ")"; |
| 464 return false; |
| 465 } |
| 466 |
| 467 // Iterate over string pieces and substitute variables, escaping as necessary. |
| 468 size_t output_string_length = 0; |
| 469 std::vector<std::string> processed_sandbox_pieces(raw_sandbox_pieces.size()); |
| 470 for (std::vector<std::string>::iterator it = raw_sandbox_pieces.begin(); |
| 471 it != raw_sandbox_pieces.end(); |
| 472 ++it) { |
| 473 std::string new_piece; |
| 474 SandboxVariableSubstitions::iterator replacement_it = |
| 475 substitutions.find(*it); |
| 476 if (replacement_it == substitutions.end()) { |
| 477 new_piece = *it; |
| 478 } else { |
| 479 // Found something to substitute. |
| 480 SandboxSubstring& replacement = replacement_it->second; |
| 481 switch (replacement.type()) { |
| 482 case SandboxSubstring::PLAIN: |
| 483 new_piece = replacement.value(); |
| 484 break; |
| 485 |
| 486 case SandboxSubstring::LITERAL: |
| 487 if (!QuotePlainString(replacement.value(), &new_piece)) |
| 488 FatalStringQuoteException(replacement.value()); |
| 489 break; |
| 490 |
| 491 case SandboxSubstring::REGEX: |
| 492 if (!QuoteStringForRegex(replacement.value(), &new_piece)) |
| 493 FatalStringQuoteException(replacement.value()); |
| 494 break; |
| 495 } |
| 496 } |
| 497 output_string_length += new_piece.size(); |
| 498 processed_sandbox_pieces.push_back(new_piece); |
| 499 } |
| 500 |
| 501 // Build final output string. |
| 502 final_sandbox_profile_str->reserve(output_string_length); |
| 503 |
| 504 for (std::vector<std::string>::iterator it = processed_sandbox_pieces.begin(); |
| 505 it != processed_sandbox_pieces.end(); |
| 506 ++it) { |
| 507 final_sandbox_profile_str->append(*it); |
| 508 } |
| 509 return true; |
| 510 } |
| 511 |
| 512 |
440 // Turns on the OS X sandbox for this process. | 513 // Turns on the OS X sandbox for this process. |
441 | 514 |
442 // static | 515 // static |
443 bool Sandbox::EnableSandbox(int sandbox_type, | 516 bool Sandbox::EnableSandbox(int sandbox_type, |
444 const base::FilePath& allowed_dir) { | 517 const base::FilePath& allowed_dir) { |
445 // Sanity - currently only SANDBOX_TYPE_UTILITY supports a directory being | 518 // Sanity - currently only SANDBOX_TYPE_UTILITY supports a directory being |
446 // passed in. | 519 // passed in. |
447 if (sandbox_type < SANDBOX_TYPE_AFTER_LAST_TYPE && | 520 if (sandbox_type < SANDBOX_TYPE_AFTER_LAST_TYPE && |
448 sandbox_type != SANDBOX_TYPE_UTILITY) { | 521 sandbox_type != SANDBOX_TYPE_UTILITY) { |
449 DCHECK(allowed_dir.empty()) | 522 DCHECK(allowed_dir.empty()) |
450 << "Only SANDBOX_TYPE_UTILITY allows a custom directory parameter."; | 523 << "Only SANDBOX_TYPE_UTILITY allows a custom directory parameter."; |
451 } | 524 } |
452 | 525 |
453 NSString* sandbox_data = LoadSandboxTemplate(sandbox_type); | 526 NSString* sandbox_data = LoadSandboxTemplate(sandbox_type); |
454 if (!sandbox_data) { | 527 if (!sandbox_data) { |
455 return false; | 528 return false; |
456 } | 529 } |
457 | 530 |
458 SandboxCompiler compiler([sandbox_data UTF8String]); | 531 SandboxVariableSubstitions substitutions; |
| 532 if (!allowed_dir.empty()) { |
| 533 // Add the sandbox commands necessary to access the given directory. |
| 534 // Note: this function must be called before PostProcessSandboxProfile() |
| 535 // since the string it inserts contains variables that need substitution. |
| 536 NSString* allowed_dir_sandbox_command = |
| 537 BuildAllowDirectoryAccessSandboxString(allowed_dir, &substitutions); |
459 | 538 |
460 if (!allowed_dir.empty()) { | 539 if (allowed_dir_sandbox_command) { // May be nil if function fails. |
461 // Add the sandbox parameters necessary to access the given directory. | 540 sandbox_data = [sandbox_data |
462 base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); | 541 stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" |
463 std::string regex; | 542 withString:allowed_dir_sandbox_command]; |
464 if (!QuoteStringForRegex(allowed_dir_canonical.value(), ®ex)) { | |
465 FatalStringQuoteException(allowed_dir_canonical.value()); | |
466 return false; | |
467 } | 543 } |
468 if (!compiler.InsertStringParam("PERMITTED_DIR", regex)) | |
469 return false; | |
470 } | 544 } |
471 | 545 |
| 546 NSMutableArray* tokens_to_remove = [NSMutableArray array]; |
| 547 |
472 // Enable verbose logging if enabled on the command line. (See common.sb | 548 // Enable verbose logging if enabled on the command line. (See common.sb |
473 // for details). | 549 // for details). |
474 const base::CommandLine* command_line = | 550 const base::CommandLine* command_line = |
475 base::CommandLine::ForCurrentProcess(); | 551 base::CommandLine::ForCurrentProcess(); |
476 bool enable_logging = | 552 bool enable_logging = |
477 command_line->HasSwitch(switches::kEnableSandboxLogging);; | 553 command_line->HasSwitch(switches::kEnableSandboxLogging);; |
478 if (!compiler.InsertBooleanParam("ENABLE_LOGGING", enable_logging)) | 554 if (enable_logging) { |
479 return false; | 555 [tokens_to_remove addObject:@";ENABLE_LOGGING"]; |
| 556 } |
| 557 |
| 558 bool lion_or_later = base::mac::IsOSLionOrLater(); |
480 | 559 |
481 // Without this, the sandbox will print a message to the system log every | 560 // Without this, the sandbox will print a message to the system log every |
482 // time it denies a request. This floods the console with useless spew. | 561 // time it denies a request. This floods the console with useless spew. |
483 if (!compiler.InsertBooleanParam("DISABLE_SANDBOX_DENIAL_LOGGING", | 562 if (!enable_logging) { |
484 !enable_logging)) | 563 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = |
485 return false; | 564 SandboxSubstring("(with no-log)"); |
| 565 } else { |
| 566 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = SandboxSubstring(""); |
| 567 } |
486 | 568 |
487 // Splice the path of the user's home directory into the sandbox profile | 569 // Splice the path of the user's home directory into the sandbox profile |
488 // (see renderer.sb for details). | 570 // (see renderer.sb for details). |
489 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; | 571 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; |
490 | 572 |
491 base::FilePath home_dir_canonical = | 573 base::FilePath home_dir_canonical = |
492 GetCanonicalSandboxPath(base::FilePath(home_dir)); | 574 GetCanonicalSandboxPath(base::FilePath(home_dir)); |
493 | 575 |
494 std::string quoted_home_dir; | 576 substitutions["USER_HOMEDIR_AS_LITERAL"] = |
495 if (!QuotePlainString(home_dir_canonical.value(), "ed_home_dir)) { | 577 SandboxSubstring(home_dir_canonical.value(), |
496 FatalStringQuoteException(home_dir_canonical.value()); | 578 SandboxSubstring::LITERAL); |
497 return false; | 579 |
| 580 if (lion_or_later) { |
| 581 // >=10.7 Sandbox rules. |
| 582 [tokens_to_remove addObject:@";10.7_OR_ABOVE"]; |
498 } | 583 } |
499 | 584 |
500 if (!compiler.InsertStringParam("USER_HOMEDIR_AS_LITERAL", quoted_home_dir)) | 585 substitutions["COMPONENT_BUILD_WORKAROUND"] = SandboxSubstring(""); |
501 return false; | |
502 | |
503 bool lion_or_later = base::mac::IsOSLionOrLater(); | |
504 if (!compiler.InsertBooleanParam("LION_OR_LATER", lion_or_later)) | |
505 return false; | |
506 | |
507 #if defined(COMPONENT_BUILD) | 586 #if defined(COMPONENT_BUILD) |
508 // dlopen() fails without file-read-metadata access if the executable image | 587 // dlopen() fails without file-read-metadata access if the executable image |
509 // contains LC_RPATH load commands. The components build uses those. | 588 // contains LC_RPATH load commands. The components build uses those. |
510 // See http://crbug.com/127465 | 589 // See http://crbug.com/127465 |
511 if (base::mac::IsOSSnowLeopard()) { | 590 if (base::mac::IsOSSnowLeopard()) { |
512 if (!compiler.InsertBooleanParam("COMPONENT_BUILD_WORKAROUND", true)) | 591 base::FilePath bundle_executable = base::mac::NSStringToFilePath( |
513 return false; | 592 [base::mac::MainBundle() executablePath]); |
| 593 NSString* sandbox_command = AllowMetadataForPath( |
| 594 GetCanonicalSandboxPath(bundle_executable)); |
| 595 substitutions["COMPONENT_BUILD_WORKAROUND"] = |
| 596 SandboxSubstring(base::SysNSStringToUTF8(sandbox_command)); |
514 } | 597 } |
515 #endif | 598 #endif |
516 | 599 |
| 600 // All information needed to assemble the final profile has been collected. |
| 601 // Merge it all together. |
| 602 std::string final_sandbox_profile_str; |
| 603 if (!PostProcessSandboxProfile(sandbox_data, tokens_to_remove, substitutions, |
| 604 &final_sandbox_profile_str)) { |
| 605 return false; |
| 606 } |
| 607 |
517 // Initialize sandbox. | 608 // Initialize sandbox. |
518 std::string error_str; | 609 char* error_buff = NULL; |
519 bool success = compiler.CompileAndApplyProfile(&error_str); | 610 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); |
520 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; | 611 bool success = (error == 0 && error_buff == NULL); |
| 612 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " |
| 613 << error |
| 614 << " " |
| 615 << error_buff; |
| 616 sandbox_free_error(error_buff); |
521 gSandboxIsActive = success; | 617 gSandboxIsActive = success; |
522 return success; | 618 return success; |
523 } | 619 } |
524 | 620 |
525 // static | 621 // static |
526 bool Sandbox::SandboxIsCurrentlyActive() { | 622 bool Sandbox::SandboxIsCurrentlyActive() { |
527 return gSandboxIsActive; | 623 return gSandboxIsActive; |
528 } | 624 } |
529 | 625 |
530 // static | 626 // static |
531 base::FilePath Sandbox::GetCanonicalSandboxPath(const base::FilePath& path) { | 627 base::FilePath Sandbox::GetCanonicalSandboxPath(const base::FilePath& path) { |
532 base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 628 base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
533 if (!fd.is_valid()) { | 629 if (!fd.is_valid()) { |
534 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 630 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
535 << path.value(); | 631 << path.value(); |
536 return path; | 632 return path; |
537 } | 633 } |
538 | 634 |
539 base::FilePath::CharType canonical_path[MAXPATHLEN]; | 635 base::FilePath::CharType canonical_path[MAXPATHLEN]; |
540 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { | 636 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { |
541 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 637 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
542 << path.value(); | 638 << path.value(); |
543 return path; | 639 return path; |
544 } | 640 } |
545 | 641 |
546 return base::FilePath(canonical_path); | 642 return base::FilePath(canonical_path); |
547 } | 643 } |
548 | 644 |
549 } // namespace content | 645 } // namespace content |
OLD | NEW |