Index: chrome/common/sandbox_mac.mm |
diff --git a/chrome/common/sandbox_mac.mm b/chrome/common/sandbox_mac.mm |
index 608ba27b5691e5d33f10f7666e7997927ffd03fa..1940c60ec5179a2affbd7b8d0aaa8743abd6be6b 100644 |
--- a/chrome/common/sandbox_mac.mm |
+++ b/chrome/common/sandbox_mac.mm |
@@ -242,6 +242,78 @@ void SandboxWarmup() { |
} |
} |
+// Build the Sandbox command necessary to allow access to a named directory |
+// indicated by |allowed_dir|. |
+// returns a string containing the sandbox profile commands necesary to allow |
+// access to that directory or nil if an error occured. |
+NSString* BuildAllowDirectoryAccessSandboxString(const FilePath& allowed_dir) { |
+ // A whitelist is used to determine which directories can be statted |
+ // This means that in the case of an /a/b/c/d/ directory, we may be able to |
+ // stat the leaf directory, but not it's parent. |
+ // The extension code in Chrome calls realpath() which fails if it can't call |
+ // stat() on one of the parent directories in the path. |
+ // The solution to this is to allow statting the parent directories themselves |
+ // but not their contents. We need to add a separate rule for each parent |
+ // directory. |
+ |
+ // The sandbox only understands "real" paths. This resolving step is |
+ // needed so the caller doesn't need to worry about things like /var |
+ // being a link to /private/var (like in the paths CreateNewTempDirectory() |
+ // returns). |
+ FilePath allowed_dir_canonical(allowed_dir); |
+ GetCanonicalSandboxPath(&allowed_dir_canonical); |
+ |
+ // Collect a list of all parent directories. |
+ FilePath last_path = allowed_dir_canonical; |
+ std::vector<FilePath> subpaths; |
+ for (FilePath path = allowed_dir_canonical.DirName(); |
+ path.value() != last_path.value(); |
+ path = path.DirName()) { |
+ subpaths.push_back(path); |
+ last_path = path; |
+ } |
+ |
+ // Iterate through all parents and allow stat() on them explicitly. |
+ NSString* sandbox_command = @"(allow file-read-metadata "; |
+ for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); |
+ i != subpaths.rend(); |
+ ++i) { |
+ std::string subdir_escaped; |
+ if (!QuotePlainString(i->value(), &subdir_escaped)) { |
+ LOG(FATAL) << "String quoting failed " << i->value(); |
+ return nil; |
+ } |
+ |
+ NSString* subdir_escaped_ns = |
+ base::SysUTF8ToNSString(subdir_escaped.c_str()); |
+ sandbox_command = |
+ [sandbox_command stringByAppendingFormat:@"(literal \"%@\")", |
+ subdir_escaped_ns]; |
+ } |
+ |
+ // Finally append the leaf directory. Unlike it's parents (for which only |
+ // stat() should be allowed), the leaf directory needs full access. |
+ sandbox_command = |
+ [sandbox_command |
+ stringByAppendingString:@") (allow file-read* file-write* "]; |
+ |
+ std::string allowed_dir_escaped; |
+ if (!QuoteStringForRegex(allowed_dir_canonical.value(), |
+ &allowed_dir_escaped)) { |
+ LOG(FATAL) << "Regex string quoting failed " |
+ << allowed_dir_canonical.value(); |
+ return nil; |
+ } |
+ |
+ NSString* allowed_dir_canonical_ns = |
+ base::SysUTF8ToNSString(allowed_dir_escaped.c_str()); |
+ sandbox_command = |
+ [sandbox_command stringByAppendingFormat:@"(regex #\"%@\") )", |
+ allowed_dir_canonical_ns]; |
+ |
+ return sandbox_command; |
+} |
+ |
// Turns on the OS X sandbox for this process. |
bool EnableSandbox(SandboxProcessType sandbox_type, |
const FilePath& allowed_dir) { |
@@ -341,28 +413,14 @@ bool EnableSandbox(SandboxProcessType sandbox_type, |
} |
if (!allowed_dir.empty()) { |
- // The sandbox only understands "real" paths. This resolving step is |
- // needed so the caller doesn't need to worry about things like /var |
- // being a link to /private/var (like in the paths CreateNewTempDirectory() |
- // returns). |
- FilePath allowed_dir_canonical(allowed_dir); |
- GetCanonicalSandboxPath(&allowed_dir_canonical); |
- |
- std::string allowed_dir_escaped; |
- if (!QuoteStringForRegex(allowed_dir_canonical.value(), |
- &allowed_dir_escaped)) { |
- LOG(FATAL) << "Regex string quoting failed " << allowed_dir.value(); |
- return false; |
- } |
- NSString* allowed_dir_escaped_ns = base::SysUTF8ToNSString( |
- allowed_dir_escaped.c_str()); |
- sandbox_data = [sandbox_data |
- stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" |
- withString:@""]; |
- sandbox_data = [sandbox_data |
- stringByReplacingOccurrencesOfString:@"DIR_TO_ALLOW_ACCESS" |
- withString:allowed_dir_escaped_ns]; |
+ NSString* allowed_dir_sandbox_command = |
+ BuildAllowDirectoryAccessSandboxString(allowed_dir); |
+ if (allowed_dir_sandbox_command) { // May be nil if function fails. |
+ sandbox_data = [sandbox_data |
+ stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" |
+ withString:allowed_dir_sandbox_command]; |
+ } |
} |
if (snow_leopard_or_higher) { |