Index: content/common/sandbox_mac.mm |
diff --git a/content/common/sandbox_mac.mm b/content/common/sandbox_mac.mm |
index a13aaf773727135c8f6c4bba513a5dc5db7951e2..45ada98368ca5bf618f5e366f044085fa8f8f490 100644 |
--- a/content/common/sandbox_mac.mm |
+++ b/content/common/sandbox_mac.mm |
@@ -43,6 +43,15 @@ extern "C" { |
extern "C" { |
void CGSSetDenyWindowServerConnections(bool); |
void CGSShutdownServerConnections(); |
+ |
+void* sandbox_create_params(); |
+int sandbox_set_param(void* params, const char* key, const char* value); |
+void* sandbox_compile_string(const char* profile_str, |
+ void* params, |
+ char** error); |
+int sandbox_apply(void* profile); |
+void sandbox_free_params(void* params); |
+void sandbox_free_profile(void* profile); |
}; |
namespace content { |
@@ -116,37 +125,59 @@ NOINLINE void FatalStringQuoteException(const std::string& str) { |
} // namespace |
-// static |
-NSString* Sandbox::AllowMetadataForPath(const base::FilePath& allowed_path) { |
- // Collect a list of all parent directories. |
- base::FilePath last_path = allowed_path; |
- std::vector<base::FilePath> subpaths; |
- for (base::FilePath path = allowed_path; |
- path.value() != last_path.value(); |
- path = path.DirName()) { |
- subpaths.push_back(path); |
- last_path = path; |
- } |
+SandboxCompiler::SandboxCompiler(const std::string& profile_str) |
+ : params_map_(), profile_str_(profile_str) { |
+} |
- // Iterate through all parents and allow stat() on them explicitly. |
- NSString* sandbox_command = @"(allow file-read-metadata "; |
- for (std::vector<base::FilePath>::reverse_iterator i = subpaths.rbegin(); |
- i != subpaths.rend(); |
- ++i) { |
- std::string subdir_escaped; |
- if (!QuotePlainString(i->value(), &subdir_escaped)) { |
- FatalStringQuoteException(i->value()); |
- return nil; |
- } |
+SandboxCompiler::~SandboxCompiler() { |
+} |
+ |
+void SandboxCompiler::InsertBooleanParam(const std::string& key, bool value) { |
+ params_map_.insert( |
+ std::pair<std::string, std::string>(key, value ? "TRUE" : "FALSE")); |
Robert Sesek
2015/06/22 20:40:23
Use std::make_pair(), and on line 142.
Greg K
2015/06/23 19:05:15
Done.
|
+} |
+ |
+void SandboxCompiler::InsertStringParam(const std::string& key, |
+ const std::string& value) { |
+ params_map_.insert(std::pair<std::string, std::string>(key, value)); |
+} |
+ |
+void SandboxCompiler::FreeSandboxResources(void* profile, |
+ void* params, |
+ char* error) { |
+ if (error) |
+ sandbox_free_error(error); |
+ if (params) |
+ sandbox_free_params(params); |
+ if (profile) |
+ sandbox_free_profile(profile); |
+} |
+ |
+bool SandboxCompiler::CompileAndApplyProfile(std::string* error) { |
+ char* error_internal = nullptr; |
+ void* profile = nullptr; |
+ void* params = nullptr; |
- NSString* subdir_escaped_ns = |
- base::SysUTF8ToNSString(subdir_escaped.c_str()); |
- sandbox_command = |
- [sandbox_command stringByAppendingFormat:@"(literal \"%@\")", |
- subdir_escaped_ns]; |
+ if (!params_map_.empty()) { |
+ params = sandbox_create_params(); |
+ if (!params) |
+ return false; |
+ |
+ for (const auto& kv : params_map_) |
+ sandbox_set_param(params, kv.first.c_str(), kv.second.c_str()); |
} |
- return [sandbox_command stringByAppendingString:@")"]; |
+ profile = |
+ sandbox_compile_string(profile_str_.c_str(), params, &error_internal); |
+ if (!profile) { |
+ error->assign(error_internal); |
+ FreeSandboxResources(profile, params, error_internal); |
+ return false; |
+ } |
+ |
+ int result = sandbox_apply(profile); |
+ FreeSandboxResources(profile, params, error_internal); |
+ return result == 0; |
} |
// static |
@@ -349,41 +380,6 @@ void Sandbox::SandboxWarmup(int sandbox_type) { |
} |
} |
-// static |
-NSString* Sandbox::BuildAllowDirectoryAccessSandboxString( |
- const base::FilePath& allowed_dir, |
- SandboxVariableSubstitions* substitutions) { |
- // 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 its 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). |
- base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
- |
- NSString* sandbox_command = AllowMetadataForPath(allowed_dir_canonical); |
- sandbox_command = [sandbox_command |
- substringToIndex:[sandbox_command length] - 1]; // strip trailing ')' |
- |
- // Finally append the leaf directory. Unlike its parents (for which only |
- // stat() should be allowed), the leaf directory needs full access. |
- (*substitutions)["ALLOWED_DIR"] = |
- SandboxSubstring(allowed_dir_canonical.value(), |
- SandboxSubstring::REGEX); |
- sandbox_command = |
- [sandbox_command |
- stringByAppendingString:@") (allow file-read* file-write*" |
- " (regex #\"@ALLOWED_DIR@\") )"]; |
- return sandbox_command; |
-} |
- |
// Load the appropriate template for the given sandbox type. |
// Returns the template as an NSString or nil on error. |
NSString* LoadSandboxTemplate(int sandbox_type) { |
@@ -441,75 +437,6 @@ NSString* LoadSandboxTemplate(int sandbox_type) { |
return [common_sandbox_prefix_data stringByAppendingString:sandbox_data]; |
} |
-// static |
-bool Sandbox::PostProcessSandboxProfile( |
- NSString* sandbox_template, |
- NSArray* comments_to_remove, |
- SandboxVariableSubstitions& substitutions, |
- std::string *final_sandbox_profile_str) { |
- NSString* sandbox_data = [[sandbox_template copy] autorelease]; |
- |
- // Remove comments, e.g. ;10.7_OR_ABOVE . |
- for (NSString* to_remove in comments_to_remove) { |
- sandbox_data = [sandbox_data stringByReplacingOccurrencesOfString:to_remove |
- withString:@""]; |
- } |
- |
- // Split string on "@" characters. |
- std::vector<std::string> raw_sandbox_pieces; |
- if (Tokenize([sandbox_data UTF8String], "@", &raw_sandbox_pieces) == 0) { |
- DLOG(FATAL) << "Bad Sandbox profile, should contain at least one token (" |
- << [sandbox_data UTF8String] |
- << ")"; |
- return false; |
- } |
- |
- // Iterate over string pieces and substitute variables, escaping as necessary. |
- size_t output_string_length = 0; |
- std::vector<std::string> processed_sandbox_pieces(raw_sandbox_pieces.size()); |
- for (std::vector<std::string>::iterator it = raw_sandbox_pieces.begin(); |
- it != raw_sandbox_pieces.end(); |
- ++it) { |
- std::string new_piece; |
- SandboxVariableSubstitions::iterator replacement_it = |
- substitutions.find(*it); |
- if (replacement_it == substitutions.end()) { |
- new_piece = *it; |
- } else { |
- // Found something to substitute. |
- SandboxSubstring& replacement = replacement_it->second; |
- switch (replacement.type()) { |
- case SandboxSubstring::PLAIN: |
- new_piece = replacement.value(); |
- break; |
- |
- case SandboxSubstring::LITERAL: |
- if (!QuotePlainString(replacement.value(), &new_piece)) |
- FatalStringQuoteException(replacement.value()); |
- break; |
- |
- case SandboxSubstring::REGEX: |
- if (!QuoteStringForRegex(replacement.value(), &new_piece)) |
- FatalStringQuoteException(replacement.value()); |
- break; |
- } |
- } |
- output_string_length += new_piece.size(); |
- processed_sandbox_pieces.push_back(new_piece); |
- } |
- |
- // Build final output string. |
- final_sandbox_profile_str->reserve(output_string_length); |
- |
- for (std::vector<std::string>::iterator it = processed_sandbox_pieces.begin(); |
- it != processed_sandbox_pieces.end(); |
- ++it) { |
- final_sandbox_profile_str->append(*it); |
- } |
- return true; |
-} |
- |
- |
// Turns on the OS X sandbox for this process. |
// static |
@@ -528,43 +455,31 @@ bool Sandbox::EnableSandbox(int sandbox_type, |
return false; |
} |
- SandboxVariableSubstitions substitutions; |
+ SandboxCompiler compiler([sandbox_data UTF8String]); |
+ |
if (!allowed_dir.empty()) { |
- // Add the sandbox commands necessary to access the given directory. |
- // Note: this function must be called before PostProcessSandboxProfile() |
- // since the string it inserts contains variables that need substitution. |
- NSString* allowed_dir_sandbox_command = |
- BuildAllowDirectoryAccessSandboxString(allowed_dir, &substitutions); |
- |
- if (allowed_dir_sandbox_command) { // May be nil if function fails. |
- sandbox_data = [sandbox_data |
- stringByReplacingOccurrencesOfString:@";ENABLE_DIRECTORY_ACCESS" |
- withString:allowed_dir_sandbox_command]; |
+ // Add the sandbox parameters necessary to access the given directory. |
+ base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
+ std::string regex; |
+ if (!QuoteStringForRegex(allowed_dir_canonical.value(), ®ex)) { |
+ FatalStringQuoteException(allowed_dir_canonical.value()); |
+ return false; |
} |
+ compiler.InsertStringParam("PERMITTED_DIR", regex); |
} |
- NSMutableArray* tokens_to_remove = [NSMutableArray array]; |
- |
// Enable verbose logging if enabled on the command line. (See common.sb |
// for details). |
const base::CommandLine* command_line = |
base::CommandLine::ForCurrentProcess(); |
bool enable_logging = |
command_line->HasSwitch(switches::kEnableSandboxLogging);; |
- if (enable_logging) { |
- [tokens_to_remove addObject:@";ENABLE_LOGGING"]; |
- } |
- |
- bool lion_or_later = base::mac::IsOSLionOrLater(); |
+ compiler.InsertBooleanParam("ENABLE_LOGGING", enable_logging); |
// Without this, the sandbox will print a message to the system log every |
// time it denies a request. This floods the console with useless spew. |
- if (!enable_logging) { |
- substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = |
- SandboxSubstring("(with no-log)"); |
- } else { |
- substitutions["DISABLE_SANDBOX_DENIAL_LOGGING"] = SandboxSubstring(""); |
- } |
+ compiler.InsertBooleanParam("DISABLE_SANDBOX_DENIAL_LOGGING", |
+ !enable_logging); |
// Splice the path of the user's home directory into the sandbox profile |
// (see renderer.sb for details). |
@@ -573,47 +488,30 @@ bool Sandbox::EnableSandbox(int sandbox_type, |
base::FilePath home_dir_canonical = |
GetCanonicalSandboxPath(base::FilePath(home_dir)); |
- substitutions["USER_HOMEDIR_AS_LITERAL"] = |
- SandboxSubstring(home_dir_canonical.value(), |
- SandboxSubstring::LITERAL); |
- |
- if (lion_or_later) { |
- // >=10.7 Sandbox rules. |
- [tokens_to_remove addObject:@";10.7_OR_ABOVE"]; |
+ std::string quoted_home_dir; |
+ if (!QuotePlainString(home_dir_canonical.value(), "ed_home_dir)) { |
+ FatalStringQuoteException(home_dir_canonical.value()); |
+ return false; |
} |
- substitutions["COMPONENT_BUILD_WORKAROUND"] = SandboxSubstring(""); |
+ compiler.InsertStringParam("USER_HOMEDIR_AS_LITERAL", quoted_home_dir); |
+ |
+ bool lion_or_later = base::mac::IsOSLionOrLater(); |
+ compiler.InsertBooleanParam("LION_OR_LATER", lion_or_later); |
+ |
#if defined(COMPONENT_BUILD) |
// dlopen() fails without file-read-metadata access if the executable image |
// contains LC_RPATH load commands. The components build uses those. |
// See http://crbug.com/127465 |
if (base::mac::IsOSSnowLeopard()) { |
- base::FilePath bundle_executable = base::mac::NSStringToFilePath( |
- [base::mac::MainBundle() executablePath]); |
- NSString* sandbox_command = AllowMetadataForPath( |
- GetCanonicalSandboxPath(bundle_executable)); |
- substitutions["COMPONENT_BUILD_WORKAROUND"] = |
- SandboxSubstring(base::SysNSStringToUTF8(sandbox_command)); |
+ compiler.InsertBooleanParam("COMPONENT_BUILD_WORKAROUND", true); |
} |
#endif |
- // All information needed to assemble the final profile has been collected. |
- // Merge it all together. |
- std::string final_sandbox_profile_str; |
- if (!PostProcessSandboxProfile(sandbox_data, tokens_to_remove, substitutions, |
- &final_sandbox_profile_str)) { |
- return false; |
- } |
- |
// Initialize sandbox. |
- char* error_buff = NULL; |
- int error = sandbox_init(final_sandbox_profile_str.c_str(), 0, &error_buff); |
- bool success = (error == 0 && error_buff == NULL); |
- DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " |
- << error |
- << " " |
- << error_buff; |
- sandbox_free_error(error_buff); |
+ std::string error_str; |
+ bool success = compiler.CompileAndApplyProfile(&error_str); |
+ DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; |
gSandboxIsActive = success; |
return success; |
} |