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 3 // found in the LICENSE file. 4 5 #include "content/browser/child_process_security_policy_impl.h" 6 7 #include "base/command_line.h" 8 #include "base/files/file_path.h" 9 #include "base/logging.h" 10 #include "base/metrics/histogram.h" 11 #include "base/platform_file.h" 12 #include "base/stl_util.h" 13 #include "base/strings/string_util.h" 14 #include "content/browser/site_instance_impl.h" 15 #include "content/public/browser/content_browser_client.h" 16 #include "content/public/browser/render_process_host.h" 17 #include "content/public/common/bindings_policy.h" 18 #include "content/public/common/content_switches.h" 19 #include "content/public/common/url_constants.h" 20 #include "net/base/net_util.h" 21 #include "net/url_request/url_request.h" 22 #include "url/gurl.h" 23 #include "webkit/browser/fileapi/file_permission_policy.h" 24 #include "webkit/browser/fileapi/file_system_url.h" 25 #include "webkit/browser/fileapi/isolated_context.h" 26 #include "webkit/common/fileapi/file_system_util.h" 27 28 namespace content { 29 30 namespace { 31 32 const int kReadFilePermissions = 33 base::PLATFORM_FILE_OPEN | 34 base::PLATFORM_FILE_READ | 35 base::PLATFORM_FILE_EXCLUSIVE_READ | 36 base::PLATFORM_FILE_ASYNC; 37 38 const int kWriteFilePermissions = 39 base::PLATFORM_FILE_OPEN | 40 base::PLATFORM_FILE_WRITE | 41 base::PLATFORM_FILE_APPEND | 42 base::PLATFORM_FILE_EXCLUSIVE_WRITE | 43 base::PLATFORM_FILE_ASYNC | 44 base::PLATFORM_FILE_WRITE_ATTRIBUTES; 45 46 const int kCreateFilePermissions = 47 base::PLATFORM_FILE_CREATE; 48 49 const int kEnumerateDirectoryPermissions = 50 kReadFilePermissions | 51 base::PLATFORM_FILE_ENUMERATE; 52 53 // TODO(tommycli): These flag sets need some work to make more obvious. 54 // Why for instance, does Create|Write != Create|Write? http://crbug.com/263150 55 const int kCreateReadWriteFilePermissions = 56 kReadFilePermissions | 57 kWriteFilePermissions | 58 kCreateFilePermissions | 59 base::PLATFORM_FILE_OPEN_ALWAYS | 60 base::PLATFORM_FILE_CREATE_ALWAYS | 61 base::PLATFORM_FILE_OPEN_TRUNCATED; 62 63 const int kCreateWriteFilePermissions = 64 kWriteFilePermissions | 65 kCreateFilePermissions | 66 base::PLATFORM_FILE_OPEN_ALWAYS | 67 base::PLATFORM_FILE_CREATE_ALWAYS | 68 base::PLATFORM_FILE_OPEN_TRUNCATED; 69 70 } // namespace 71 72 // The SecurityState class is used to maintain per-child process security state 73 // information. 74 class ChildProcessSecurityPolicyImpl::SecurityState { 75 public: 76 SecurityState() 77 : enabled_bindings_(0), 78 can_read_raw_cookies_(false) { } 79 80 ~SecurityState() { 81 scheme_policy_.clear(); 82 fileapi::IsolatedContext* isolated_context = 83 fileapi::IsolatedContext::GetInstance(); 84 for (FileSystemMap::iterator iter = filesystem_permissions_.begin(); 85 iter != filesystem_permissions_.end(); 86 ++iter) { 87 isolated_context->RemoveReference(iter->first); 88 } 89 UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.PerChildFilePermissions", 90 file_permissions_.size()); 91 } 92 93 // Grant permission to request URLs with the specified scheme. 94 void GrantScheme(const std::string& scheme) { 95 scheme_policy_[scheme] = true; 96 } 97 98 // Revoke permission to request URLs with the specified scheme. 99 void RevokeScheme(const std::string& scheme) { 100 scheme_policy_[scheme] = false; 101 } 102 103 // Grant certain permissions to a file. 104 void GrantPermissionsForFile(const base::FilePath& file, int permissions) { 105 base::FilePath stripped = file.StripTrailingSeparators(); 106 file_permissions_[stripped] |= permissions; 107 UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.FilePermissionPathLength", 108 stripped.value().size()); 109 } 110 111 // Grant navigation to a file but not the file:// scheme in general. 112 void GrantRequestOfSpecificFile(const base::FilePath &file) { 113 request_file_set_.insert(file.StripTrailingSeparators()); 114 } 115 116 // Revokes all permissions granted to a file. 117 void RevokeAllPermissionsForFile(const base::FilePath& file) { 118 base::FilePath stripped = file.StripTrailingSeparators(); 119 file_permissions_.erase(stripped); 120 request_file_set_.erase(stripped); 121 } 122 123 // Grant certain permissions to a file. 124 void GrantPermissionsForFileSystem(const std::string& filesystem_id, 125 int permissions) { 126 if (filesystem_permissions_.find(filesystem_id) == 127 filesystem_permissions_.end()) 128 fileapi::IsolatedContext::GetInstance()->AddReference(filesystem_id); 129 filesystem_permissions_[filesystem_id] |= permissions; 130 } 131 132 bool HasPermissionsForFileSystem(const std::string& filesystem_id, 133 int permissions) { 134 if (filesystem_permissions_.find(filesystem_id) == 135 filesystem_permissions_.end()) 136 return false; 137 return (filesystem_permissions_[filesystem_id] & permissions) == 138 permissions; 139 } 140 141 void GrantBindings(int bindings) { 142 enabled_bindings_ |= bindings; 143 } 144 145 void GrantReadRawCookies() { 146 can_read_raw_cookies_ = true; 147 } 148 149 void RevokeReadRawCookies() { 150 can_read_raw_cookies_ = false; 151 } 152 153 // Determine whether permission has been granted to request |url|. 154 bool CanRequestURL(const GURL& url) { 155 // Having permission to a scheme implies permssion to all of its URLs. 156 SchemeMap::const_iterator judgment(scheme_policy_.find(url.scheme())); 157 if (judgment != scheme_policy_.end()) 158 return judgment->second; 159 160 // file:// URLs are more granular. The child may have been given 161 // permission to a specific file but not the file:// scheme in general. 162 if (url.SchemeIs(chrome::kFileScheme)) { 163 base::FilePath path; 164 if (net::FileURLToFilePath(url, &path)) 165 return request_file_set_.find(path) != request_file_set_.end(); 166 } 167 168 return false; // Unmentioned schemes are disallowed. 169 } 170 171 // Determine if the certain permissions have been granted to a file. 172 bool HasPermissionsForFile(const base::FilePath& file, int permissions) { 173 if (!permissions || file.empty() || !file.IsAbsolute()) 174 return false; 175 base::FilePath current_path = file.StripTrailingSeparators(); 176 base::FilePath last_path; 177 int skip = 0; 178 while (current_path != last_path) { 179 base::FilePath base_name = current_path.BaseName(); 180 if (base_name.value() == base::FilePath::kParentDirectory) { 181 ++skip; 182 } else if (skip > 0) { 183 if (base_name.value() != base::FilePath::kCurrentDirectory) 184 --skip; 185 } else { 186 if (file_permissions_.find(current_path) != file_permissions_.end()) 187 return (file_permissions_[current_path] & permissions) == permissions; 188 } 189 last_path = current_path; 190 current_path = current_path.DirName(); 191 } 192 193 return false; 194 } 195 196 bool CanLoadPage(const GURL& gurl) { 197 if (origin_lock_.is_empty()) 198 return true; 199 200 // TODO(creis): We must pass the valid browser_context to convert hosted 201 // apps URLs. Currently, hosted apps cannot be loaded in this mode. 202 // See http://crbug.com/160576. 203 GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl); 204 return origin_lock_ == site_gurl; 205 } 206 207 bool CanAccessCookiesForOrigin(const GURL& gurl) { 208 if (origin_lock_.is_empty()) 209 return true; 210 // TODO(creis): We must pass the valid browser_context to convert hosted 211 // apps URLs. Currently, hosted apps cannot set cookies in this mode. 212 // See http://crbug.com/160576. 213 GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl); 214 return origin_lock_ == site_gurl; 215 } 216 217 bool CanSendCookiesForOrigin(const GURL& gurl) { 218 // We only block cross-site cookies on network requests if the 219 // --enable-strict-site-isolation flag is passed. This is expected to break 220 // compatibility with many sites. The similar --site-per-process flag only 221 // blocks JavaScript access to cross-site cookies (in 222 // CanAccessCookiesForOrigin). 223 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 224 if (!command_line.HasSwitch(switches::kEnableStrictSiteIsolation)) 225 return true; 226 227 if (origin_lock_.is_empty()) 228 return true; 229 // TODO(creis): We must pass the valid browser_context to convert hosted 230 // apps URLs. Currently, hosted apps cannot set cookies in this mode. 231 // See http://crbug.com/160576. 232 GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl); 233 return origin_lock_ == site_gurl; 234 } 235 236 void LockToOrigin(const GURL& gurl) { 237 origin_lock_ = gurl; 238 } 239 240 bool has_web_ui_bindings() const { 241 return enabled_bindings_ & BINDINGS_POLICY_WEB_UI; 242 } 243 244 bool can_read_raw_cookies() const { 245 return can_read_raw_cookies_; 246 } 247 248 private: 249 typedef std::map<std::string, bool> SchemeMap; 250 251 typedef int FilePermissionFlags; // bit-set of PlatformFileFlags 252 typedef std::map<base::FilePath, FilePermissionFlags> FileMap; 253 typedef std::map<std::string, FilePermissionFlags> FileSystemMap; 254 typedef std::set<base::FilePath> FileSet; 255 256 // Maps URL schemes to whether permission has been granted or revoked: 257 // |true| means the scheme has been granted. 258 // |false| means the scheme has been revoked. 259 // If a scheme is not present in the map, then it has never been granted 260 // or revoked. 261 SchemeMap scheme_policy_; 262 263 // The set of files the child process is permited to upload to the web. 264 FileMap file_permissions_; 265 266 // The set of files the child process is permitted to load. 267 FileSet request_file_set_; 268 269 int enabled_bindings_; 270 271 bool can_read_raw_cookies_; 272 273 GURL origin_lock_; 274 275 // The set of isolated filesystems the child process is permitted to access. 276 FileSystemMap filesystem_permissions_; 277 278 DISALLOW_COPY_AND_ASSIGN(SecurityState); 279 }; 280 281 ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() { 282 // We know about these schemes and believe them to be safe. 283 RegisterWebSafeScheme(chrome::kHttpScheme); 284 RegisterWebSafeScheme(chrome::kHttpsScheme); 285 RegisterWebSafeScheme(chrome::kFtpScheme); 286 RegisterWebSafeScheme(chrome::kDataScheme); 287 RegisterWebSafeScheme("feed"); 288 RegisterWebSafeScheme(chrome::kBlobScheme); 289 RegisterWebSafeScheme(chrome::kFileSystemScheme); 290 291 // We know about the following pseudo schemes and treat them specially. 292 RegisterPseudoScheme(chrome::kAboutScheme); 293 RegisterPseudoScheme(chrome::kJavaScriptScheme); 294 RegisterPseudoScheme(kViewSourceScheme); 295 } 296 297 ChildProcessSecurityPolicyImpl::~ChildProcessSecurityPolicyImpl() { 298 web_safe_schemes_.clear(); 299 pseudo_schemes_.clear(); 300 STLDeleteContainerPairSecondPointers(security_state_.begin(), 301 security_state_.end()); 302 security_state_.clear(); 303 } 304 305 // static 306 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { 307 return ChildProcessSecurityPolicyImpl::GetInstance(); 308 } 309 310 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() { 311 return Singleton<ChildProcessSecurityPolicyImpl>::get(); 312 } 313 314 void ChildProcessSecurityPolicyImpl::Add(int child_id) { 315 base::AutoLock lock(lock_); 316 AddChild(child_id); 317 } 318 319 void ChildProcessSecurityPolicyImpl::AddWorker(int child_id, 320 int main_render_process_id) { 321 base::AutoLock lock(lock_); 322 AddChild(child_id); 323 worker_map_[child_id] = main_render_process_id; 324 } 325 326 void ChildProcessSecurityPolicyImpl::Remove(int child_id) { 327 base::AutoLock lock(lock_); 328 if (!security_state_.count(child_id)) 329 return; // May be called multiple times. 330 331 delete security_state_[child_id]; 332 security_state_.erase(child_id); 333 worker_map_.erase(child_id); 334 } 335 336 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme( 337 const std::string& scheme) { 338 base::AutoLock lock(lock_); 339 DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once."; 340 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not pseudo."; 341 342 web_safe_schemes_.insert(scheme); 343 } 344 345 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme( 346 const std::string& scheme) { 347 base::AutoLock lock(lock_); 348 349 return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end()); 350 } 351 352 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme( 353 const std::string& scheme) { 354 base::AutoLock lock(lock_); 355 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once."; 356 DCHECK(web_safe_schemes_.count(scheme) == 0) << 357 "Pseudo implies not web-safe."; 358 359 pseudo_schemes_.insert(scheme); 360 } 361 362 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme( 363 const std::string& scheme) { 364 base::AutoLock lock(lock_); 365 366 return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); 367 } 368 369 void ChildProcessSecurityPolicyImpl::GrantRequestURL( 370 int child_id, const GURL& url) { 371 372 if (!url.is_valid()) 373 return; // Can't grant the capability to request invalid URLs. 374 375 if (IsWebSafeScheme(url.scheme())) 376 return; // The scheme has already been whitelisted for every child process. 377 378 if (IsPseudoScheme(url.scheme())) { 379 // The view-source scheme is a special case of a pseudo-URL that eventually 380 // results in requesting its embedded URL. 381 if (url.SchemeIs(kViewSourceScheme)) { 382 // URLs with the view-source scheme typically look like: 383 // view-source:http://www.google.com/a 384 // In order to request these URLs, the child_id needs to be able to 385 // request the embedded URL. 386 GrantRequestURL(child_id, GURL(url.GetContent())); 387 } 388 389 return; // Can't grant the capability to request pseudo schemes. 390 } 391 392 { 393 base::AutoLock lock(lock_); 394 SecurityStateMap::iterator state = security_state_.find(child_id); 395 if (state == security_state_.end()) 396 return; 397 398 // When the child process has been commanded to request this scheme, 399 // we grant it the capability to request all URLs of that scheme. 400 state->second->GrantScheme(url.scheme()); 401 } 402 } 403 404 void ChildProcessSecurityPolicyImpl::GrantRequestSpecificFileURL( 405 int child_id, 406 const GURL& url) { 407 if (!url.SchemeIs(chrome::kFileScheme)) 408 return; 409 410 { 411 base::AutoLock lock(lock_); 412 SecurityStateMap::iterator state = security_state_.find(child_id); 413 if (state == security_state_.end()) 414 return; 415 416 // When the child process has been commanded to request a file:// URL, 417 // then we grant it the capability for that URL only. 418 base::FilePath path; 419 if (net::FileURLToFilePath(url, &path)) 420 state->second->GrantRequestOfSpecificFile(path); 421 } 422 } 423 424 void ChildProcessSecurityPolicyImpl::GrantReadFile(int child_id, 425 const base::FilePath& file) { 426 GrantPermissionsForFile(child_id, file, kReadFilePermissions); 427 } 428 429 void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFile( 430 int child_id, const base::FilePath& file) { 431 GrantPermissionsForFile(child_id, file, kCreateReadWriteFilePermissions); 432 } 433 434 void ChildProcessSecurityPolicyImpl::GrantCreateWriteFile( 435 int child_id, const base::FilePath& file) { 436 GrantPermissionsForFile(child_id, file, kCreateWriteFilePermissions); 437 } 438 439 void ChildProcessSecurityPolicyImpl::GrantReadDirectory( 440 int child_id, const base::FilePath& directory) { 441 GrantPermissionsForFile(child_id, directory, kEnumerateDirectoryPermissions); 442 } 443 444 void ChildProcessSecurityPolicyImpl::GrantPermissionsForFile( 445 int child_id, const base::FilePath& file, int permissions) { 446 base::AutoLock lock(lock_); 447 448 SecurityStateMap::iterator state = security_state_.find(child_id); 449 if (state == security_state_.end()) 450 return; 451 452 state->second->GrantPermissionsForFile(file, permissions); 453 } 454 455 void ChildProcessSecurityPolicyImpl::RevokeAllPermissionsForFile( 456 int child_id, const base::FilePath& file) { 457 base::AutoLock lock(lock_); 458 459 SecurityStateMap::iterator state = security_state_.find(child_id); 460 if (state == security_state_.end()) 461 return; 462 463 state->second->RevokeAllPermissionsForFile(file); 464 } 465 466 void ChildProcessSecurityPolicyImpl::GrantReadFileSystem( 467 int child_id, const std::string& filesystem_id) { 468 GrantPermissionsForFileSystem(child_id, filesystem_id, kReadFilePermissions); 469 } 470 471 void ChildProcessSecurityPolicyImpl::GrantWriteFileSystem( 472 int child_id, const std::string& filesystem_id) { 473 GrantPermissionsForFileSystem(child_id, filesystem_id, kWriteFilePermissions); 474 } 475 476 void ChildProcessSecurityPolicyImpl::GrantCreateFileForFileSystem( 477 int child_id, const std::string& filesystem_id) { 478 GrantPermissionsForFileSystem(child_id, filesystem_id, 479 kCreateFilePermissions); 480 } 481 482 void ChildProcessSecurityPolicyImpl::GrantCopyIntoFileSystem( 483 int child_id, const std::string& filesystem_id) { 484 // TODO(tommycli): These granted permissions a bit too broad, but not abused. 485 // We are fixing in http://crbug.com/262142 and associated CL. 486 GrantPermissionsForFileSystem(child_id, filesystem_id, 487 kCreateFilePermissions); 488 } 489 490 void ChildProcessSecurityPolicyImpl::GrantScheme(int child_id, 491 const std::string& scheme) { 492 base::AutoLock lock(lock_); 493 494 SecurityStateMap::iterator state = security_state_.find(child_id); 495 if (state == security_state_.end()) 496 return; 497 498 state->second->GrantScheme(scheme); 499 } 500 501 void ChildProcessSecurityPolicyImpl::GrantWebUIBindings(int child_id) { 502 base::AutoLock lock(lock_); 503 504 SecurityStateMap::iterator state = security_state_.find(child_id); 505 if (state == security_state_.end()) 506 return; 507 508 state->second->GrantBindings(BINDINGS_POLICY_WEB_UI); 509 510 // Web UI bindings need the ability to request chrome: URLs. 511 state->second->GrantScheme(chrome::kChromeUIScheme); 512 513 // Web UI pages can contain links to file:// URLs. 514 state->second->GrantScheme(chrome::kFileScheme); 515 } 516 517 void ChildProcessSecurityPolicyImpl::GrantReadRawCookies(int child_id) { 518 base::AutoLock lock(lock_); 519 520 SecurityStateMap::iterator state = security_state_.find(child_id); 521 if (state == security_state_.end()) 522 return; 523 524 state->second->GrantReadRawCookies(); 525 } 526 527 void ChildProcessSecurityPolicyImpl::RevokeReadRawCookies(int child_id) { 528 base::AutoLock lock(lock_); 529 530 SecurityStateMap::iterator state = security_state_.find(child_id); 531 if (state == security_state_.end()) 532 return; 533 534 state->second->RevokeReadRawCookies(); 535 } 536 537 bool ChildProcessSecurityPolicyImpl::CanLoadPage( 538 int child_id, 539 const GURL& url, 540 ResourceType::Type resource_type) { 541 // If --site-per-process flag is passed, we should enforce 542 // stronger security restrictions on page navigation. 543 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && 544 ResourceType::IsFrame(resource_type)) { 545 // TODO(nasko): Do the proper check for site-per-process, once 546 // out-of-process iframes is ready to go. 547 return true; 548 } 549 return true; 550 } 551 552 bool ChildProcessSecurityPolicyImpl::CanRequestURL( 553 int child_id, const GURL& url) { 554 if (!url.is_valid()) 555 return false; // Can't request invalid URLs. 556 557 if (IsWebSafeScheme(url.scheme())) 558 return true; // The scheme has been white-listed for every child process. 559 560 if (IsPseudoScheme(url.scheme())) { 561 // There are a number of special cases for pseudo schemes. 562 563 if (url.SchemeIs(kViewSourceScheme)) { 564 // A view-source URL is allowed if the child process is permitted to 565 // request the embedded URL. Careful to avoid pointless recursion. 566 GURL child_url(url.GetContent()); 567 if (child_url.SchemeIs(kViewSourceScheme) && 568 url.SchemeIs(kViewSourceScheme)) 569 return false; 570 571 return CanRequestURL(child_id, child_url); 572 } 573 574 if (LowerCaseEqualsASCII(url.spec(), kAboutBlankURL)) 575 return true; // Every child process can request <about:blank>. 576 577 // URLs like <about:memory> and <about:crash> shouldn't be requestable by 578 // any child process. Also, this case covers <javascript:...>, which should 579 // be handled internally by the process and not kicked up to the browser. 580 return false; 581 } 582 583 if (!GetContentClient()->browser()->IsHandledURL(url) && 584 !net::URLRequest::IsHandledURL(url)) { 585 return true; // This URL request is destined for ShellExecute. 586 } 587 588 { 589 base::AutoLock lock(lock_); 590 591 SecurityStateMap::iterator state = security_state_.find(child_id); 592 if (state == security_state_.end()) 593 return false; 594 595 // Otherwise, we consult the child process's security state to see if it is 596 // allowed to request the URL. 597 return state->second->CanRequestURL(url); 598 } 599 } 600 601 bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id, 602 const base::FilePath& file) { 603 return HasPermissionsForFile(child_id, file, kReadFilePermissions); 604 } 605 606 bool ChildProcessSecurityPolicyImpl::CanWriteFile(int child_id, 607 const base::FilePath& file) { 608 return HasPermissionsForFile(child_id, file, kWriteFilePermissions); 609 } 610 611 bool ChildProcessSecurityPolicyImpl::CanCreateFile(int child_id, 612 const base::FilePath& file) { 613 return HasPermissionsForFile(child_id, file, kCreateFilePermissions); 614 } 615 616 bool ChildProcessSecurityPolicyImpl::CanCreateWriteFile( 617 int child_id, 618 const base::FilePath& file) { 619 return HasPermissionsForFile(child_id, file, kCreateWriteFilePermissions); 620 } 621 622 bool ChildProcessSecurityPolicyImpl::CanReadDirectory( 623 int child_id, const base::FilePath& directory) { 624 return HasPermissionsForFile(child_id, 625 directory, 626 kEnumerateDirectoryPermissions); 627 } 628 629 bool ChildProcessSecurityPolicyImpl::CanReadFileSystem( 630 int child_id, const std::string& filesystem_id) { 631 return HasPermissionsForFileSystem(child_id, 632 filesystem_id, 633 kReadFilePermissions); 634 } 635 636 bool ChildProcessSecurityPolicyImpl::CanReadWriteFileSystem( 637 int child_id, const std::string& filesystem_id) { 638 return HasPermissionsForFileSystem(child_id, 639 filesystem_id, 640 kReadFilePermissions | 641 kWriteFilePermissions); 642 } 643 644 bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystem( 645 int child_id, const std::string& filesystem_id) { 646 // TODO(tommycli): These granted permissions a bit too broad, but not abused. 647 // We are fixing in http://crbug.com/262142 and associated CL. 648 return HasPermissionsForFileSystem(child_id, 649 filesystem_id, 650 kCreateFilePermissions); 651 } 652 653 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile( 654 int child_id, const base::FilePath& file, int permissions) { 655 base::AutoLock lock(lock_); 656 bool result = ChildProcessHasPermissionsForFile(child_id, file, permissions); 657 if (!result) { 658 // If this is a worker thread that has no access to a given file, 659 // let's check that its renderer process has access to that file instead. 660 WorkerToMainProcessMap::iterator iter = worker_map_.find(child_id); 661 if (iter != worker_map_.end() && iter->second != 0) { 662 result = ChildProcessHasPermissionsForFile(iter->second, 663 file, 664 permissions); 665 } 666 } 667 return result; 668 } 669 670 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile( 671 int child_id, const fileapi::FileSystemURL& url, int permissions) { 672 if (!url.is_valid()) 673 return false; 674 675 if (url.path().ReferencesParent()) 676 return false; 677 678 // Any write access is disallowed on the root path. 679 if (fileapi::VirtualPath::IsRootPath(url.path()) && 680 (permissions & ~kReadFilePermissions)) { 681 return false; 682 } 683 684 if (url.mount_type() == fileapi::kFileSystemTypeIsolated) { 685 // When Isolated filesystems is overlayed on top of another filesystem, 686 // its per-filesystem permission overrides the underlying filesystem 687 // permissions). 688 return HasPermissionsForFileSystem( 689 child_id, url.mount_filesystem_id(), permissions); 690 } 691 692 FileSystemPermissionPolicyMap::iterator found = 693 file_system_policy_map_.find(url.type()); 694 if (found == file_system_policy_map_.end()) 695 return false; 696 697 if ((found->second & fileapi::FILE_PERMISSION_READ_ONLY) && 698 permissions & ~kReadFilePermissions) { 699 return false; 700 } 701 702 if (found->second & fileapi::FILE_PERMISSION_USE_FILE_PERMISSION) 703 return HasPermissionsForFile(child_id, url.path(), permissions); 704 705 if (found->second & fileapi::FILE_PERMISSION_SANDBOX) 706 return true; 707 708 return false; 709 } 710 711 bool ChildProcessSecurityPolicyImpl::CanReadFileSystemFile( 712 int child_id, 713 const fileapi::FileSystemURL& url) { 714 return HasPermissionsForFileSystemFile(child_id, url, kReadFilePermissions); 715 } 716 717 bool ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile( 718 int child_id, 719 const fileapi::FileSystemURL& url) { 720 return HasPermissionsForFileSystemFile(child_id, url, kWriteFilePermissions); 721 } 722 723 bool ChildProcessSecurityPolicyImpl::CanCreateFileSystemFile( 724 int child_id, 725 const fileapi::FileSystemURL& url) { 726 return HasPermissionsForFileSystemFile(child_id, url, kCreateFilePermissions); 727 } 728 729 bool ChildProcessSecurityPolicyImpl::CanCreateWriteFileSystemFile( 730 int child_id, 731 const fileapi::FileSystemURL& url) { 732 return HasPermissionsForFileSystemFile(child_id, url, 733 kCreateWriteFilePermissions); 734 } 735 736 bool ChildProcessSecurityPolicyImpl::HasWebUIBindings(int child_id) { 737 base::AutoLock lock(lock_); 738 739 SecurityStateMap::iterator state = security_state_.find(child_id); 740 if (state == security_state_.end()) 741 return false; 742 743 return state->second->has_web_ui_bindings(); 744 } 745 746 bool ChildProcessSecurityPolicyImpl::CanReadRawCookies(int child_id) { 747 base::AutoLock lock(lock_); 748 749 SecurityStateMap::iterator state = security_state_.find(child_id); 750 if (state == security_state_.end()) 751 return false; 752 753 return state->second->can_read_raw_cookies(); 754 } 755 756 void ChildProcessSecurityPolicyImpl::AddChild(int child_id) { 757 if (security_state_.count(child_id) != 0) { 758 NOTREACHED() << "Add child process at most once."; 759 return; 760 } 761 762 security_state_[child_id] = new SecurityState(); 763 } 764 765 bool ChildProcessSecurityPolicyImpl::ChildProcessHasPermissionsForFile( 766 int child_id, const base::FilePath& file, int permissions) { 767 SecurityStateMap::iterator state = security_state_.find(child_id); 768 if (state == security_state_.end()) 769 return false; 770 return state->second->HasPermissionsForFile(file, permissions); 771 } 772 773 bool ChildProcessSecurityPolicyImpl::CanAccessCookiesForOrigin( 774 int child_id, const GURL& gurl) { 775 base::AutoLock lock(lock_); 776 SecurityStateMap::iterator state = security_state_.find(child_id); 777 if (state == security_state_.end()) 778 return false; 779 return state->second->CanAccessCookiesForOrigin(gurl); 780 } 781 782 bool ChildProcessSecurityPolicyImpl::CanSendCookiesForOrigin(int child_id, 783 const GURL& gurl) { 784 base::AutoLock lock(lock_); 785 SecurityStateMap::iterator state = security_state_.find(child_id); 786 if (state == security_state_.end()) 787 return false; 788 return state->second->CanSendCookiesForOrigin(gurl); 789 } 790 791 void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id, 792 const GURL& gurl) { 793 // "gurl" can be currently empty in some cases, such as file://blah. 794 DCHECK(SiteInstanceImpl::GetSiteForURL(NULL, gurl) == gurl); 795 base::AutoLock lock(lock_); 796 SecurityStateMap::iterator state = security_state_.find(child_id); 797 DCHECK(state != security_state_.end()); 798 state->second->LockToOrigin(gurl); 799 } 800 801 void ChildProcessSecurityPolicyImpl::GrantPermissionsForFileSystem( 802 int child_id, 803 const std::string& filesystem_id, 804 int permission) { 805 base::AutoLock lock(lock_); 806 807 SecurityStateMap::iterator state = security_state_.find(child_id); 808 if (state == security_state_.end()) 809 return; 810 state->second->GrantPermissionsForFileSystem(filesystem_id, permission); 811 } 812 813 bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystem( 814 int child_id, 815 const std::string& filesystem_id, 816 int permission) { 817 base::AutoLock lock(lock_); 818 819 SecurityStateMap::iterator state = security_state_.find(child_id); 820 if (state == security_state_.end()) 821 return false; 822 return state->second->HasPermissionsForFileSystem(filesystem_id, permission); 823 } 824 825 void ChildProcessSecurityPolicyImpl::RegisterFileSystemPermissionPolicy( 826 fileapi::FileSystemType type, 827 int policy) { 828 base::AutoLock lock(lock_); 829 file_system_policy_map_[type] = policy; 830 } 831 832 } // namespace content 833