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