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); |
46 }; | 55 }; |
47 | 56 |
48 namespace content { | 57 namespace content { |
49 namespace { | 58 namespace { |
50 | 59 |
51 // Is the sandbox currently active. | 60 // Is the sandbox currently active. |
52 bool gSandboxIsActive = false; | 61 bool gSandboxIsActive = false; |
53 | 62 |
54 struct SandboxTypeToResourceIDMapping { | 63 struct SandboxTypeToResourceIDMapping { |
55 SandboxType sandbox_type; | 64 SandboxType sandbox_type; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 // in a central place. | 118 // in a central place. |
110 NOINLINE void FatalStringQuoteException(const std::string& str) { | 119 NOINLINE void FatalStringQuoteException(const std::string& str) { |
111 // Copy bad string to the stack so it's recorded in the crash dump. | 120 // Copy bad string to the stack so it's recorded in the crash dump. |
112 char bad_string[256] = {0}; | 121 char bad_string[256] = {0}; |
113 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); | 122 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); |
114 DLOG(FATAL) << "String quoting failed " << bad_string; | 123 DLOG(FATAL) << "String quoting failed " << bad_string; |
115 } | 124 } |
116 | 125 |
117 } // namespace | 126 } // namespace |
118 | 127 |
119 // static | 128 SandboxCompiler::SandboxCompiler(const std::string& profile_str) |
120 NSString* Sandbox::AllowMetadataForPath(const base::FilePath& allowed_path) { | 129 : params_map_(), profile_str_(profile_str) { |
121 // Collect a list of all parent directories. | 130 } |
122 base::FilePath last_path = allowed_path; | 131 |
123 std::vector<base::FilePath> subpaths; | 132 SandboxCompiler::~SandboxCompiler() { |
124 for (base::FilePath path = allowed_path; | 133 } |
125 path.value() != last_path.value(); | 134 |
126 path = path.DirName()) { | 135 bool SandboxCompiler::InsertBooleanParam(const std::string& key, bool value) { |
127 subpaths.push_back(path); | 136 return params_map_.insert(std::make_pair(key, value ? "TRUE" : "FALSE")) |
128 last_path = path; | 137 .second; |
| 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()); |
129 } | 168 } |
130 | 169 |
131 // Iterate through all parents and allow stat() on them explicitly. | 170 profile = |
132 NSString* sandbox_command = @"(allow file-read-metadata "; | 171 sandbox_compile_string(profile_str_.c_str(), params, &error_internal); |
133 for (std::vector<base::FilePath>::reverse_iterator i = subpaths.rbegin(); | 172 if (!profile) { |
134 i != subpaths.rend(); | 173 error->assign(error_internal); |
135 ++i) { | 174 FreeSandboxResources(profile, params, error_internal); |
136 std::string subdir_escaped; | 175 return false; |
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]; | |
147 } | 176 } |
148 | 177 |
149 return [sandbox_command stringByAppendingString:@")"]; | 178 int result = sandbox_apply(profile); |
| 179 FreeSandboxResources(profile, params, error_internal); |
| 180 return result == 0; |
150 } | 181 } |
151 | 182 |
152 // static | 183 // static |
153 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { | 184 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { |
154 dst->clear(); | 185 dst->clear(); |
155 | 186 |
156 const char* src = src_utf8.c_str(); | 187 const char* src = src_utf8.c_str(); |
157 int32_t length = src_utf8.length(); | 188 int32_t length = src_utf8.length(); |
158 int32_t position = 0; | 189 int32_t position = 0; |
159 while (position < length) { | 190 while (position < length) { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 // Shutting down the connection requires connecting to WindowServer, | 373 // Shutting down the connection requires connecting to WindowServer, |
343 // so do this before actually engaging the sandbox. This is only done on | 374 // so do this before actually engaging the sandbox. This is only done on |
344 // 10.8 and higher because doing it on earlier OSes causes layout tests to | 375 // 10.8 and higher because doing it on earlier OSes causes layout tests to |
345 // fail <http://crbug.com/397642#c48>. This may cause two log messages to | 376 // fail <http://crbug.com/397642#c48>. This may cause two log messages to |
346 // be printed to the system logger on certain OS versions. | 377 // be printed to the system logger on certain OS versions. |
347 CGSSetDenyWindowServerConnections(true); | 378 CGSSetDenyWindowServerConnections(true); |
348 CGSShutdownServerConnections(); | 379 CGSShutdownServerConnections(); |
349 } | 380 } |
350 } | 381 } |
351 | 382 |
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 | |
387 // Load the appropriate template for the given sandbox type. | 383 // Load the appropriate template for the given sandbox type. |
388 // Returns the template as an NSString or nil on error. | 384 // Returns the template as an NSString or nil on error. |
389 NSString* LoadSandboxTemplate(int sandbox_type) { | 385 NSString* LoadSandboxTemplate(int sandbox_type) { |
390 // We use a custom sandbox definition to lock things down as tightly as | 386 // We use a custom sandbox definition to lock things down as tightly as |
391 // possible. | 387 // possible. |
392 int sandbox_profile_resource_id = -1; | 388 int sandbox_profile_resource_id = -1; |
393 | 389 |
394 // Find resource id for sandbox profile to use for the specific sandbox type. | 390 // Find resource id for sandbox profile to use for the specific sandbox type. |
395 for (size_t i = 0; | 391 for (size_t i = 0; |
396 i < arraysize(kDefaultSandboxTypeToResourceIDMapping); | 392 i < arraysize(kDefaultSandboxTypeToResourceIDMapping); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 | 430 |
435 base::scoped_nsobject<NSString> sandbox_data( | 431 base::scoped_nsobject<NSString> sandbox_data( |
436 [[NSString alloc] initWithBytes:sandbox_definition.data() | 432 [[NSString alloc] initWithBytes:sandbox_definition.data() |
437 length:sandbox_definition.length() | 433 length:sandbox_definition.length() |
438 encoding:NSUTF8StringEncoding]); | 434 encoding:NSUTF8StringEncoding]); |
439 | 435 |
440 // Prefix sandbox_data with common_sandbox_prefix_data. | 436 // Prefix sandbox_data with common_sandbox_prefix_data. |
441 return [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; | 437 return [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; |
442 } | 438 } |
443 | 439 |
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 | |
513 // Turns on the OS X sandbox for this process. | 440 // Turns on the OS X sandbox for this process. |
514 | 441 |
515 // static | 442 // static |
516 bool Sandbox::EnableSandbox(int sandbox_type, | 443 bool Sandbox::EnableSandbox(int sandbox_type, |
517 const base::FilePath& allowed_dir) { | 444 const base::FilePath& allowed_dir) { |
518 // Sanity - currently only SANDBOX_TYPE_UTILITY supports a directory being | 445 // Sanity - currently only SANDBOX_TYPE_UTILITY supports a directory being |
519 // passed in. | 446 // passed in. |
520 if (sandbox_type < SANDBOX_TYPE_AFTER_LAST_TYPE && | 447 if (sandbox_type < SANDBOX_TYPE_AFTER_LAST_TYPE && |
521 sandbox_type != SANDBOX_TYPE_UTILITY) { | 448 sandbox_type != SANDBOX_TYPE_UTILITY) { |
522 DCHECK(allowed_dir.empty()) | 449 DCHECK(allowed_dir.empty()) |
523 << "Only SANDBOX_TYPE_UTILITY allows a custom directory parameter."; | 450 << "Only SANDBOX_TYPE_UTILITY allows a custom directory parameter."; |
524 } | 451 } |
525 | 452 |
526 NSString* sandbox_data = LoadSandboxTemplate(sandbox_type); | 453 NSString* sandbox_data = LoadSandboxTemplate(sandbox_type); |
527 if (!sandbox_data) { | 454 if (!sandbox_data) { |
528 return false; | 455 return false; |
529 } | 456 } |
530 | 457 |
531 SandboxVariableSubstitions substitutions; | 458 SandboxCompiler compiler([sandbox_data UTF8String]); |
| 459 |
532 if (!allowed_dir.empty()) { | 460 if (!allowed_dir.empty()) { |
533 // Add the sandbox commands necessary to access the given directory. | 461 // Add the sandbox parameters necessary to access the given directory. |
534 // Note: this function must be called before PostProcessSandboxProfile() | 462 base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
535 // since the string it inserts contains variables that need substitution. | 463 std::string regex; |
536 NSString* allowed_dir_sandbox_command = | 464 if (!QuoteStringForRegex(allowed_dir_canonical.value(), ®ex)) { |
537 BuildAllowDirectoryAccessSandboxString(allowed_dir, &substitutions); | 465 FatalStringQuoteException(allowed_dir_canonical.value()); |
538 | 466 return false; |
539 if (allowed_dir_sandbox_command) { // May be nil if function fails. | |
540 sandbox_data = [sandbox_data | |
541 stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" | |
542 withString:allowed_dir_sandbox_command]; | |
543 } | 467 } |
| 468 if (!compiler.InsertStringParam("PERMITTED_DIR", regex)) |
| 469 return false; |
544 } | 470 } |
545 | 471 |
546 NSMutableArray* tokens_to_remove = [NSMutableArray array]; | |
547 | |
548 // Enable verbose logging if enabled on the command line. (See common.sb | 472 // Enable verbose logging if enabled on the command line. (See common.sb |
549 // for details). | 473 // for details). |
550 const base::CommandLine* command_line = | 474 const base::CommandLine* command_line = |
551 base::CommandLine::ForCurrentProcess(); | 475 base::CommandLine::ForCurrentProcess(); |
552 bool enable_logging = | 476 bool enable_logging = |
553 command_line->HasSwitch(switches::kEnableSandboxLogging);; | 477 command_line->HasSwitch(switches::kEnableSandboxLogging);; |
554 if (enable_logging) { | 478 if (!compiler.InsertBooleanParam("ENABLE_LOGGING", enable_logging)) |
555 [tokens_to_remove addObject:@";ENABLE_LOGGING"]; | 479 return false; |
556 } | |
557 | |
558 bool lion_or_later = base::mac::IsOSLionOrLater(); | |
559 | 480 |
560 // Without this, the sandbox will print a message to the system log every | 481 // Without this, the sandbox will print a message to the system log every |
561 // time it denies a request. This floods the console with useless spew. | 482 // time it denies a request. This floods the console with useless spew. |
562 if (!enable_logging) { | 483 if (!compiler.InsertBooleanParam("DISABLE_SANDBOX_DENIAL_LOGGING", |
563 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = | 484 !enable_logging)) |
564 SandboxSubstring("(with no-log)"); | 485 return false; |
565 } else { | |
566 substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = SandboxSubstring(""); | |
567 } | |
568 | 486 |
569 // Splice the path of the user's home directory into the sandbox profile | 487 // Splice the path of the user's home directory into the sandbox profile |
570 // (see renderer.sb for details). | 488 // (see renderer.sb for details). |
571 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; | 489 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; |
572 | 490 |
573 base::FilePath home_dir_canonical = | 491 base::FilePath home_dir_canonical = |
574 GetCanonicalSandboxPath(base::FilePath(home_dir)); | 492 GetCanonicalSandboxPath(base::FilePath(home_dir)); |
575 | 493 |
576 substitutions["USER_HOMEDIR_AS_LITERAL"] = | 494 std::string quoted_home_dir; |
577 SandboxSubstring(home_dir_canonical.value(), | 495 if (!QuotePlainString(home_dir_canonical.value(), "ed_home_dir)) { |
578 SandboxSubstring::LITERAL); | 496 FatalStringQuoteException(home_dir_canonical.value()); |
579 | 497 return false; |
580 if (lion_or_later) { | |
581 // >=10.7 Sandbox rules. | |
582 [tokens_to_remove addObject:@";10.7_OR_ABOVE"]; | |
583 } | 498 } |
584 | 499 |
585 substitutions["COMPONENT_BUILD_WORKAROUND"] = SandboxSubstring(""); | 500 if (!compiler.InsertStringParam("USER_HOMEDIR_AS_LITERAL", quoted_home_dir)) |
| 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 |
586 #if defined(COMPONENT_BUILD) | 507 #if defined(COMPONENT_BUILD) |
587 // dlopen() fails without file-read-metadata access if the executable image | 508 // dlopen() fails without file-read-metadata access if the executable image |
588 // contains LC_RPATH load commands. The components build uses those. | 509 // contains LC_RPATH load commands. The components build uses those. |
589 // See http://crbug.com/127465 | 510 // See http://crbug.com/127465 |
590 if (base::mac::IsOSSnowLeopard()) { | 511 if (base::mac::IsOSSnowLeopard()) { |
591 base::FilePath bundle_executable = base::mac::NSStringToFilePath( | 512 if (!compiler.InsertBooleanParam("COMPONENT_BUILD_WORKAROUND", true)) |
592 [base::mac::MainBundle() executablePath]); | 513 return false; |
593 NSString* sandbox_command = AllowMetadataForPath( | |
594 GetCanonicalSandboxPath(bundle_executable)); | |
595 substitutions["COMPONENT_BUILD_WORKAROUND"] = | |
596 SandboxSubstring(base::SysNSStringToUTF8(sandbox_command)); | |
597 } | 514 } |
598 #endif | 515 #endif |
599 | 516 |
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 | |
608 // Initialize sandbox. | 517 // Initialize sandbox. |
609 char* error_buff = NULL; | 518 std::string error_str; |
610 int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); | 519 bool success = compiler.CompileAndApplyProfile(&error_str); |
611 bool success = (error == 0 && error_buff == NULL); | 520 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; |
612 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " | |
613 << error | |
614 << " " | |
615 << error_buff; | |
616 sandbox_free_error(error_buff); | |
617 gSandboxIsActive = success; | 521 gSandboxIsActive = success; |
618 return success; | 522 return success; |
619 } | 523 } |
620 | 524 |
621 // static | 525 // static |
622 bool Sandbox::SandboxIsCurrentlyActive() { | 526 bool Sandbox::SandboxIsCurrentlyActive() { |
623 return gSandboxIsActive; | 527 return gSandboxIsActive; |
624 } | 528 } |
625 | 529 |
626 // static | 530 // static |
627 base::FilePath Sandbox::GetCanonicalSandboxPath(const base::FilePath& path) { | 531 base::FilePath Sandbox::GetCanonicalSandboxPath(const base::FilePath& path) { |
628 base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); | 532 base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY))); |
629 if (!fd.is_valid()) { | 533 if (!fd.is_valid()) { |
630 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 534 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
631 << path.value(); | 535 << path.value(); |
632 return path; | 536 return path; |
633 } | 537 } |
634 | 538 |
635 base::FilePath::CharType canonical_path[MAXPATHLEN]; | 539 base::FilePath::CharType canonical_path[MAXPATHLEN]; |
636 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { | 540 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { |
637 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 541 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
638 << path.value(); | 542 << path.value(); |
639 return path; | 543 return path; |
640 } | 544 } |
641 | 545 |
642 return base::FilePath(canonical_path); | 546 return base::FilePath(canonical_path); |
643 } | 547 } |
644 | 548 |
645 } // namespace content | 549 } // namespace content |
OLD | NEW |