| 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 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 { SANDBOX_TYPE_RENDERER, IDR_RENDERER_SANDBOX_PROFILE }, | 64 { SANDBOX_TYPE_RENDERER, IDR_RENDERER_SANDBOX_PROFILE }, |
| 65 { SANDBOX_TYPE_UTILITY, IDR_UTILITY_SANDBOX_PROFILE }, | 65 { SANDBOX_TYPE_UTILITY, IDR_UTILITY_SANDBOX_PROFILE }, |
| 66 { SANDBOX_TYPE_GPU, IDR_GPU_SANDBOX_PROFILE }, | 66 { SANDBOX_TYPE_GPU, IDR_GPU_SANDBOX_PROFILE }, |
| 67 { SANDBOX_TYPE_PPAPI, IDR_PPAPI_SANDBOX_PROFILE }, | 67 { SANDBOX_TYPE_PPAPI, IDR_PPAPI_SANDBOX_PROFILE }, |
| 68 }; | 68 }; |
| 69 | 69 |
| 70 static_assert(arraysize(kDefaultSandboxTypeToResourceIDMapping) == \ | 70 static_assert(arraysize(kDefaultSandboxTypeToResourceIDMapping) == \ |
| 71 size_t(SANDBOX_TYPE_AFTER_LAST_TYPE), \ | 71 size_t(SANDBOX_TYPE_AFTER_LAST_TYPE), \ |
| 72 "sandbox type to resource id mapping incorrect"); | 72 "sandbox type to resource id mapping incorrect"); |
| 73 | 73 |
| 74 // Try to escape |c| as a "SingleEscapeCharacter" (\n, etc). If successful, | |
| 75 // returns true and appends the escape sequence to |dst|. | |
| 76 bool EscapeSingleChar(char c, std::string* dst) { | |
| 77 const char *append = NULL; | |
| 78 switch (c) { | |
| 79 case '\b': | |
| 80 append = "\\b"; | |
| 81 break; | |
| 82 case '\f': | |
| 83 append = "\\f"; | |
| 84 break; | |
| 85 case '\n': | |
| 86 append = "\\n"; | |
| 87 break; | |
| 88 case '\r': | |
| 89 append = "\\r"; | |
| 90 break; | |
| 91 case '\t': | |
| 92 append = "\\t"; | |
| 93 break; | |
| 94 case '\\': | |
| 95 append = "\\\\"; | |
| 96 break; | |
| 97 case '"': | |
| 98 append = "\\\""; | |
| 99 break; | |
| 100 } | |
| 101 | |
| 102 if (!append) { | |
| 103 return false; | |
| 104 } | |
| 105 | |
| 106 dst->append(append); | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 // Errors quoting strings for the Sandbox profile are always fatal, report them | |
| 111 // in a central place. | |
| 112 NOINLINE void FatalStringQuoteException(const std::string& str) { | |
| 113 // Copy bad string to the stack so it's recorded in the crash dump. | |
| 114 char bad_string[256] = {0}; | |
| 115 base::strlcpy(bad_string, str.c_str(), arraysize(bad_string)); | |
| 116 DLOG(FATAL) << "String quoting failed " << bad_string; | |
| 117 } | |
| 118 | |
| 119 } // namespace | 74 } // namespace |
| 120 | 75 |
| 121 // static | |
| 122 bool Sandbox::QuotePlainString(const std::string& src_utf8, std::string* dst) { | |
| 123 dst->clear(); | |
| 124 | |
| 125 const char* src = src_utf8.c_str(); | |
| 126 int32_t length = src_utf8.length(); | |
| 127 int32_t position = 0; | |
| 128 while (position < length) { | |
| 129 UChar32 c; | |
| 130 U8_NEXT(src, position, length, c); // Macro increments |position|. | |
| 131 DCHECK_GE(c, 0); | |
| 132 if (c < 0) | |
| 133 return false; | |
| 134 | |
| 135 if (c < 128) { // EscapeSingleChar only handles ASCII. | |
| 136 char as_char = static_cast<char>(c); | |
| 137 if (EscapeSingleChar(as_char, dst)) { | |
| 138 continue; | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 if (c < 32 || c > 126) { | |
| 143 // Any characters that aren't printable ASCII get the \u treatment. | |
| 144 unsigned int as_uint = static_cast<unsigned int>(c); | |
| 145 base::StringAppendF(dst, "\\u%04X", as_uint); | |
| 146 continue; | |
| 147 } | |
| 148 | |
| 149 // If we got here we know that the character in question is strictly | |
| 150 // in the ASCII range so there's no need to do any kind of encoding | |
| 151 // conversion. | |
| 152 dst->push_back(static_cast<char>(c)); | |
| 153 } | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 // static | |
| 158 bool Sandbox::QuoteStringForRegex(const std::string& str_utf8, | |
| 159 std::string* dst) { | |
| 160 // Characters with special meanings in sandbox profile syntax. | |
| 161 const char regex_special_chars[] = { | |
| 162 '\\', | |
| 163 | |
| 164 // Metacharacters | |
| 165 '^', | |
| 166 '.', | |
| 167 '[', | |
| 168 ']', | |
| 169 '$', | |
| 170 '(', | |
| 171 ')', | |
| 172 '|', | |
| 173 | |
| 174 // Quantifiers | |
| 175 '*', | |
| 176 '+', | |
| 177 '?', | |
| 178 '{', | |
| 179 '}', | |
| 180 }; | |
| 181 | |
| 182 // Anchor regex at start of path. | |
| 183 dst->assign("^"); | |
| 184 | |
| 185 const char* src = str_utf8.c_str(); | |
| 186 int32_t length = str_utf8.length(); | |
| 187 int32_t position = 0; | |
| 188 while (position < length) { | |
| 189 UChar32 c; | |
| 190 U8_NEXT(src, position, length, c); // Macro increments |position|. | |
| 191 DCHECK_GE(c, 0); | |
| 192 if (c < 0) | |
| 193 return false; | |
| 194 | |
| 195 // The Mac sandbox regex parser only handles printable ASCII characters. | |
| 196 // 33 >= c <= 126 | |
| 197 if (c < 32 || c > 125) { | |
| 198 return false; | |
| 199 } | |
| 200 | |
| 201 for (size_t i = 0; i < arraysize(regex_special_chars); ++i) { | |
| 202 if (c == regex_special_chars[i]) { | |
| 203 dst->push_back('\\'); | |
| 204 break; | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 dst->push_back(static_cast<char>(c)); | |
| 209 } | |
| 210 | |
| 211 // Make sure last element of path is interpreted as a directory. Leaving this | |
| 212 // off would allow access to files if they start with the same name as the | |
| 213 // directory. | |
| 214 dst->append("(/|$)"); | |
| 215 | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 // Warm up System APIs that empirically need to be accessed before the Sandbox | 76 // Warm up System APIs that empirically need to be accessed before the Sandbox |
| 220 // is turned on. | 77 // is turned on. |
| 221 // This method is layed out in blocks, each one containing a separate function | 78 // This method is layed out in blocks, each one containing a separate function |
| 222 // that needs to be warmed up. The OS version on which we found the need to | 79 // that needs to be warmed up. The OS version on which we found the need to |
| 223 // enable the function is also noted. | 80 // enable the function is also noted. |
| 224 // This function is tested on the following OS versions: | 81 // This function is tested on the following OS versions: |
| 225 // 10.5.6, 10.6.0 | 82 // 10.5.6, 10.6.0 |
| 226 | 83 |
| 227 // static | 84 // static |
| 228 void Sandbox::SandboxWarmup(int sandbox_type) { | 85 void Sandbox::SandboxWarmup(int sandbox_type) { |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 std::string sandbox_data = LoadSandboxTemplate(sandbox_type); | 243 std::string sandbox_data = LoadSandboxTemplate(sandbox_type); |
| 387 if (sandbox_data.empty()) { | 244 if (sandbox_data.empty()) { |
| 388 return false; | 245 return false; |
| 389 } | 246 } |
| 390 | 247 |
| 391 sandbox::SandboxCompiler compiler(sandbox_data); | 248 sandbox::SandboxCompiler compiler(sandbox_data); |
| 392 | 249 |
| 393 if (!allowed_dir.empty()) { | 250 if (!allowed_dir.empty()) { |
| 394 // Add the sandbox parameters necessary to access the given directory. | 251 // Add the sandbox parameters necessary to access the given directory. |
| 395 base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); | 252 base::FilePath allowed_dir_canonical = GetCanonicalSandboxPath(allowed_dir); |
| 396 std::string regex; | 253 if (!compiler.InsertStringParam("PERMITTED_DIR", |
| 397 if (!QuoteStringForRegex(allowed_dir_canonical.value(), ®ex)) { | 254 allowed_dir_canonical.value())) |
| 398 FatalStringQuoteException(allowed_dir_canonical.value()); | |
| 399 return false; | |
| 400 } | |
| 401 if (!compiler.InsertStringParam("PERMITTED_DIR", regex)) | |
| 402 return false; | 255 return false; |
| 403 } | 256 } |
| 404 | 257 |
| 405 // Enable verbose logging if enabled on the command line. (See common.sb | 258 // Enable verbose logging if enabled on the command line. (See common.sb |
| 406 // for details). | 259 // for details). |
| 407 const base::CommandLine* command_line = | 260 const base::CommandLine* command_line = |
| 408 base::CommandLine::ForCurrentProcess(); | 261 base::CommandLine::ForCurrentProcess(); |
| 409 bool enable_logging = | 262 bool enable_logging = |
| 410 command_line->HasSwitch(switches::kEnableSandboxLogging);; | 263 command_line->HasSwitch(switches::kEnableSandboxLogging);; |
| 411 if (!compiler.InsertBooleanParam("ENABLE_LOGGING", enable_logging)) | 264 if (!compiler.InsertBooleanParam("ENABLE_LOGGING", enable_logging)) |
| 412 return false; | 265 return false; |
| 413 | 266 |
| 414 // Without this, the sandbox will print a message to the system log every | 267 // Without this, the sandbox will print a message to the system log every |
| 415 // time it denies a request. This floods the console with useless spew. | 268 // time it denies a request. This floods the console with useless spew. |
| 416 if (!compiler.InsertBooleanParam("DISABLE_SANDBOX_DENIAL_LOGGING", | 269 if (!compiler.InsertBooleanParam("DISABLE_SANDBOX_DENIAL_LOGGING", |
| 417 !enable_logging)) | 270 !enable_logging)) |
| 418 return false; | 271 return false; |
| 419 | 272 |
| 420 // Splice the path of the user's home directory into the sandbox profile | 273 // Splice the path of the user's home directory into the sandbox profile |
| 421 // (see renderer.sb for details). | 274 // (see renderer.sb for details). |
| 422 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; | 275 std::string home_dir = [NSHomeDirectory() fileSystemRepresentation]; |
| 423 | 276 |
| 424 base::FilePath home_dir_canonical = | 277 base::FilePath home_dir_canonical = |
| 425 GetCanonicalSandboxPath(base::FilePath(home_dir)); | 278 GetCanonicalSandboxPath(base::FilePath(home_dir)); |
| 426 | 279 |
| 427 std::string quoted_home_dir; | 280 if (!compiler.InsertStringParam("USER_HOMEDIR_AS_LITERAL", |
| 428 if (!QuotePlainString(home_dir_canonical.value(), "ed_home_dir)) { | 281 home_dir_canonical.value())) |
| 429 FatalStringQuoteException(home_dir_canonical.value()); | |
| 430 return false; | |
| 431 } | |
| 432 | |
| 433 if (!compiler.InsertStringParam("USER_HOMEDIR_AS_LITERAL", quoted_home_dir)) | |
| 434 return false; | 282 return false; |
| 435 | 283 |
| 436 bool elcap_or_later = base::mac::IsAtLeastOS10_11(); | 284 bool elcap_or_later = base::mac::IsAtLeastOS10_11(); |
| 437 if (!compiler.InsertBooleanParam("ELCAP_OR_LATER", elcap_or_later)) | 285 if (!compiler.InsertBooleanParam("ELCAP_OR_LATER", elcap_or_later)) |
| 438 return false; | 286 return false; |
| 439 | 287 |
| 440 // Initialize sandbox. | 288 // Initialize sandbox. |
| 441 std::string error_str; | 289 std::string error_str; |
| 442 bool success = compiler.CompileAndApplyProfile(&error_str); | 290 bool success = compiler.CompileAndApplyProfile(&error_str); |
| 443 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; | 291 DLOG_IF(FATAL, !success) << "Failed to initialize sandbox: " << error_str; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 463 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { | 311 if (HANDLE_EINTR(fcntl(fd.get(), F_GETPATH, canonical_path)) != 0) { |
| 464 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " | 312 DPLOG(FATAL) << "GetCanonicalSandboxPath() failed for: " |
| 465 << path.value(); | 313 << path.value(); |
| 466 return path; | 314 return path; |
| 467 } | 315 } |
| 468 | 316 |
| 469 return base::FilePath(canonical_path); | 317 return base::FilePath(canonical_path); |
| 470 } | 318 } |
| 471 | 319 |
| 472 } // namespace content | 320 } // namespace content |
| OLD | NEW |