child_process_security_policy_impl.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 30namespace content { 31 32namespace { 33 34const int kReadFilePermissions = 35 base::PLATFORM_FILE_OPEN | 36 base::PLATFORM_FILE_READ | 37 base::PLATFORM_FILE_EXCLUSIVE_READ | 38 base::PLATFORM_FILE_ASYNC; 39 40const int kWriteFilePermissions = 41 base::PLATFORM_FILE_OPEN | 42 base::PLATFORM_FILE_WRITE | 43 base::PLATFORM_FILE_APPEND | 44 base::PLATFORM_FILE_EXCLUSIVE_WRITE | 45 base::PLATFORM_FILE_ASYNC | 46 base::PLATFORM_FILE_WRITE_ATTRIBUTES; 47 48const int kCreateFilePermissions = 49 base::PLATFORM_FILE_CREATE; 50 51const int kEnumerateDirectoryPermissions = 52 kReadFilePermissions | 53 base::PLATFORM_FILE_ENUMERATE; 54 55// TODO(tommycli): These flag sets need some work to make more obvious. 56// Why for instance, does Create|Write != CreateWrite? http://crbug.com/263150 57const int kCreateReadWriteFilePermissions = 58 kReadFilePermissions | 59 kWriteFilePermissions | 60 kCreateFilePermissions | 61 base::PLATFORM_FILE_OPEN_ALWAYS | 62 base::PLATFORM_FILE_CREATE_ALWAYS | 63 base::PLATFORM_FILE_OPEN_TRUNCATED; 64 65} // namespace 66 67// The SecurityState class is used to maintain per-child process security state 68// information. 69class ChildProcessSecurityPolicyImpl::SecurityState { 70 public: 71 SecurityState() 72 : enabled_bindings_(0), 73 can_read_raw_cookies_(false), 74 can_send_midi_sysex_(false) { } 75 76 ~SecurityState() { 77 scheme_policy_.clear(); 78 fileapi::IsolatedContext* isolated_context = 79 fileapi::IsolatedContext::GetInstance(); 80 for (FileSystemMap::iterator iter = filesystem_permissions_.begin(); 81 iter != filesystem_permissions_.end(); 82 ++iter) { 83 isolated_context->RemoveReference(iter->first); 84 } 85 UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.PerChildFilePermissions", 86 file_permissions_.size()); 87 } 88 89 // Grant permission to request URLs with the specified scheme. 90 void GrantScheme(const std::string& scheme) { 91 scheme_policy_[scheme] = true; 92 } 93 94 // Revoke permission to request URLs with the specified scheme. 95 void RevokeScheme(const std::string& scheme) { 96 scheme_policy_[scheme] = false; 97 } 98 99 // Grant certain permissions to a file. 100 void GrantPermissionsForFile(const base::FilePath& file, int permissions) { 101 base::FilePath stripped = file.StripTrailingSeparators(); 102 file_permissions_[stripped] |= permissions; 103 UMA_HISTOGRAM_COUNTS("ChildProcessSecurityPolicy.FilePermissionPathLength", 104 stripped.value().size()); 105 } 106 107 // Grant navigation to a file but not the file:// scheme in general. 108 void GrantRequestOfSpecificFile(const base::FilePath &file) { 109 request_file_set_.insert(file.StripTrailingSeparators()); 110 } 111 112 // Revokes all permissions granted to a file. 113 void RevokeAllPermissionsForFile(const base::FilePath& file) { 114 base::FilePath stripped = file.StripTrailingSeparators(); 115 file_permissions_.erase(stripped); 116 request_file_set_.erase(stripped); 117 } 118 119 // Grant certain permissions to a file. 120 void GrantPermissionsForFileSystem(const std::string& filesystem_id, 121 int permissions) { 122 if (filesystem_permissions_.find(filesystem_id) == 123 filesystem_permissions_.end()) 124 fileapi::IsolatedContext::GetInstance()->AddReference(filesystem_id); 125 filesystem_permissions_[filesystem_id] |= permissions; 126 } 127 128 bool HasPermissionsForFileSystem(const std::string& filesystem_id, 129 int permissions) { 130 if (filesystem_permissions_.find(filesystem_id) == 131 filesystem_permissions_.end()) 132 return false; 133 return (filesystem_permissions_[filesystem_id] & permissions) == 134 permissions; 135 } 136 137 void GrantBindings(int bindings) { 138 enabled_bindings_ |= bindings; 139 } 140 141 void GrantReadRawCookies() { 142 can_read_raw_cookies_ = true; 143 } 144 145 void RevokeReadRawCookies() { 146 can_read_raw_cookies_ = false; 147 } 148 149 void GrantPermissionForMIDISysEx() { 150 can_send_midi_sysex_ = true; 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 bool can_send_midi_sysex() const { 249 return can_send_midi_sysex_; 250 } 251 252 private: 253 typedef std::map<std::string, bool> SchemeMap; 254 255 typedef int FilePermissionFlags; // bit-set of PlatformFileFlags 256 typedef std::map<base::FilePath, FilePermissionFlags> FileMap; 257 typedef std::map<std::string, FilePermissionFlags> FileSystemMap; 258 typedef std::set<base::FilePath> FileSet; 259 260 // Maps URL schemes to whether permission has been granted or revoked: 261 // |true| means the scheme has been granted. 262 // |false| means the scheme has been revoked. 263 // If a scheme is not present in the map, then it has never been granted 264 // or revoked. 265 SchemeMap scheme_policy_; 266 267 // The set of files the child process is permited to upload to the web. 268 FileMap file_permissions_; 269 270 // The set of files the child process is permitted to load. 271 FileSet request_file_set_; 272 273 int enabled_bindings_; 274 275 bool can_read_raw_cookies_; 276 277 bool can_send_midi_sysex_; 278 279 GURL origin_lock_; 280 281 // The set of isolated filesystems the child process is permitted to access. 282 FileSystemMap filesystem_permissions_; 283 284 DISALLOW_COPY_AND_ASSIGN(SecurityState); 285}; 286 287ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() { 288 // We know about these schemes and believe them to be safe. 289 RegisterWebSafeScheme(kHttpScheme); 290 RegisterWebSafeScheme(kHttpsScheme); 291 RegisterWebSafeScheme(chrome::kFtpScheme); 292 RegisterWebSafeScheme(chrome::kDataScheme); 293 RegisterWebSafeScheme("feed"); 294 RegisterWebSafeScheme(chrome::kBlobScheme); 295 RegisterWebSafeScheme(chrome::kFileSystemScheme); 296 297 // We know about the following pseudo schemes and treat them specially. 298 RegisterPseudoScheme(chrome::kAboutScheme); 299 RegisterPseudoScheme(kJavaScriptScheme); 300 RegisterPseudoScheme(kViewSourceScheme); 301} 302 303ChildProcessSecurityPolicyImpl::~ChildProcessSecurityPolicyImpl() { 304 web_safe_schemes_.clear(); 305 pseudo_schemes_.clear(); 306 STLDeleteContainerPairSecondPointers(security_state_.begin(), 307 security_state_.end()); 308 security_state_.clear(); 309} 310 311// static 312ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { 313 return ChildProcessSecurityPolicyImpl::GetInstance(); 314} 315 316ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() { 317 return Singleton<ChildProcessSecurityPolicyImpl>::get(); 318} 319 320void ChildProcessSecurityPolicyImpl::Add(int child_id) { 321 base::AutoLock lock(lock_); 322 AddChild(child_id); 323} 324 325void ChildProcessSecurityPolicyImpl::AddWorker(int child_id, 326 int main_render_process_id) { 327 base::AutoLock lock(lock_); 328 AddChild(child_id); 329 worker_map_[child_id] = main_render_process_id; 330} 331 332void ChildProcessSecurityPolicyImpl::Remove(int child_id) { 333 base::AutoLock lock(lock_); 334 if (!security_state_.count(child_id)) 335 return; // May be called multiple times. 336 337 delete security_state_[child_id]; 338 security_state_.erase(child_id); 339 worker_map_.erase(child_id); 340} 341 342void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme( 343 const std::string& scheme) { 344 base::AutoLock lock(lock_); 345 DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once."; 346 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not pseudo."; 347 348 web_safe_schemes_.insert(scheme); 349} 350 351bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme( 352 const std::string& scheme) { 353 base::AutoLock lock(lock_); 354 355 return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end()); 356} 357 358void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme( 359 const std::string& scheme) { 360 base::AutoLock lock(lock_); 361 DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once."; 362 DCHECK(web_safe_schemes_.count(scheme) == 0) << 363 "Pseudo implies not web-safe."; 364 365 pseudo_schemes_.insert(scheme); 366} 367 368bool ChildProcessSecurityPolicyImpl::IsPseudoScheme( 369 const std::string& scheme) { 370 base::AutoLock lock(lock_); 371 372 return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end()); 373} 374 375void ChildProcessSecurityPolicyImpl::GrantRequestURL( 376 int child_id, const GURL& url) { 377 378 if (!url.is_valid()) 379 return; // Can't grant the capability to request invalid URLs. 380 381 if (IsWebSafeScheme(url.scheme())) 382 return; // The scheme has already been whitelisted for every child process. 383 384 if (IsPseudoScheme(url.scheme())) { 385 // The view-source scheme is a special case of a pseudo-URL that eventually 386 // results in requesting its embedded URL. 387 if (url.SchemeIs(kViewSourceScheme)) { 388 // URLs with the view-source scheme typically look like: 389 // view-source:http://www.google.com/a 390 // In order to request these URLs, the child_id needs to be able to 391 // request the embedded URL. 392 GrantRequestURL(child_id, GURL(url.path())); 393 } 394 395 return; // Can't grant the capability to request pseudo schemes. 396 } 397 398 { 399 base::AutoLock lock(lock_); 400 SecurityStateMap::iterator state = security_state_.find(child_id); 401 if (state == security_state_.end()) 402 return; 403 404 // When the child process has been commanded to request this scheme, 405 // we grant it the capability to request all URLs of that scheme. 406 state->second->GrantScheme(url.scheme()); 407 } 408} 409 410void ChildProcessSecurityPolicyImpl::GrantRequestSpecificFileURL( 411 int child_id, 412 const GURL& url) { 413 if (!url.SchemeIs(chrome::kFileScheme)) 414 return; 415 416 { 417 base::AutoLock lock(lock_); 418 SecurityStateMap::iterator state = security_state_.find(child_id); 419 if (state == security_state_.end()) 420 return; 421 422 // When the child process has been commanded to request a file:// URL, 423 // then we grant it the capability for that URL only. 424 base::FilePath path; 425 if (net::FileURLToFilePath(url, &path)) 426 state->second->GrantRequestOfSpecificFile(path); 427 } 428} 429 430void ChildProcessSecurityPolicyImpl::GrantReadFile(int child_id, 431 const base::FilePath& file) { 432 GrantPermissionsForFile(child_id, file, kReadFilePermissions); 433} 434 435void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFile( 436 int child_id, const base::FilePath& file) { 437 GrantPermissionsForFile(child_id, file, kCreateReadWriteFilePermissions); 438} 439 440void ChildProcessSecurityPolicyImpl::GrantReadDirectory( 441 int child_id, const base::FilePath& directory) { 442 GrantPermissionsForFile(child_id, directory, kEnumerateDirectoryPermissions); 443} 444 445void ChildProcessSecurityPolicyImpl::GrantPermissionsForFile( 446 int child_id, const base::FilePath& file, int permissions) { 447 base::AutoLock lock(lock_); 448 449 SecurityStateMap::iterator state = security_state_.find(child_id); 450 if (state == security_state_.end()) 451 return; 452 453 state->second->GrantPermissionsForFile(file, permissions); 454} 455 456void ChildProcessSecurityPolicyImpl::RevokeAllPermissionsForFile( 457 int child_id, const base::FilePath& file) { 458 base::AutoLock lock(lock_); 459 460 SecurityStateMap::iterator state = security_state_.find(child_id); 461 if (state == security_state_.end()) 462 return; 463 464 state->second->RevokeAllPermissionsForFile(file); 465} 466 467void ChildProcessSecurityPolicyImpl::GrantReadFileSystem( 468 int child_id, const std::string& filesystem_id) { 469 GrantPermissionsForFileSystem(child_id, filesystem_id, kReadFilePermissions); 470} 471 472void ChildProcessSecurityPolicyImpl::GrantWriteFileSystem( 473 int child_id, const std::string& filesystem_id) { 474 GrantPermissionsForFileSystem(child_id, filesystem_id, kWriteFilePermissions); 475} 476 477void ChildProcessSecurityPolicyImpl::GrantCreateFileForFileSystem( 478 int child_id, const std::string& filesystem_id) { 479 GrantPermissionsForFileSystem(child_id, filesystem_id, 480 kCreateFilePermissions); 481} 482 483void ChildProcessSecurityPolicyImpl::GrantCopyIntoFileSystem( 484 int child_id, const std::string& filesystem_id) { 485 // TODO(tommycli): These granted permissions a bit too broad, but not abused. 486 // We are fixing in http://crbug.com/262142 and associated CL. 487 GrantPermissionsForFileSystem(child_id, filesystem_id, 488 kCreateFilePermissions); 489} 490 491void ChildProcessSecurityPolicyImpl::GrantSendMIDISysExMessage(int child_id) { 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->GrantPermissionForMIDISysEx(); 499} 500 501void ChildProcessSecurityPolicyImpl::GrantScheme(int child_id, 502 const std::string& scheme) { 503 base::AutoLock lock(lock_); 504 505 SecurityStateMap::iterator state = security_state_.find(child_id); 506 if (state == security_state_.end()) 507 return; 508 509 state->second->GrantScheme(scheme); 510} 511 512void ChildProcessSecurityPolicyImpl::GrantWebUIBindings(int child_id) { 513 base::AutoLock lock(lock_); 514 515 SecurityStateMap::iterator state = security_state_.find(child_id); 516 if (state == security_state_.end()) 517 return; 518 519 state->second->GrantBindings(BINDINGS_POLICY_WEB_UI); 520 521 // Web UI bindings need the ability to request chrome: URLs. 522 state->second->GrantScheme(chrome::kChromeUIScheme); 523 524 // Web UI pages can contain links to file:// URLs. 525 state->second->GrantScheme(chrome::kFileScheme); 526} 527 528void ChildProcessSecurityPolicyImpl::GrantReadRawCookies(int child_id) { 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->GrantReadRawCookies(); 536} 537 538void ChildProcessSecurityPolicyImpl::RevokeReadRawCookies(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->RevokeReadRawCookies(); 546} 547 548bool ChildProcessSecurityPolicyImpl::CanLoadPage( 549 int child_id, 550 const GURL& url, 551 ResourceType::Type resource_type) { 552 // If --site-per-process flag is passed, we should enforce 553 // stronger security restrictions on page navigation. 554 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && 555 ResourceType::IsFrame(resource_type)) { 556 // TODO(nasko): Do the proper check for site-per-process, once 557 // out-of-process iframes is ready to go. 558 return true; 559 } 560 return true; 561} 562 563bool ChildProcessSecurityPolicyImpl::CanRequestURL( 564 int child_id, const GURL& url) { 565 if (!url.is_valid()) 566 return false; // Can't request invalid URLs. 567 568 if (IsWebSafeScheme(url.scheme())) 569 return true; // The scheme has been white-listed for every child process. 570 571 if (IsPseudoScheme(url.scheme())) { 572 // There are a number of special cases for pseudo schemes. 573 574 if (url.SchemeIs(kViewSourceScheme)) { 575 // A view-source URL is allowed if the child process is permitted to 576 // request the embedded URL. Careful to avoid pointless recursion. 577 GURL child_url(url.path()); 578 if (child_url.SchemeIs(kViewSourceScheme) && 579 url.SchemeIs(kViewSourceScheme)) 580 return false; 581 582 return CanRequestURL(child_id, child_url); 583 } 584 585 if (LowerCaseEqualsASCII(url.spec(), kAboutBlankURL)) 586 return true; // Every child process can request <about:blank>. 587 588 // URLs like <about:memory> and <about:crash> shouldn't be requestable by 589 // any child process. Also, this case covers <javascript:...>, which should 590 // be handled internally by the process and not kicked up to the browser. 591 return false; 592 } 593 594 if (!GetContentClient()->browser()->IsHandledURL(url) && 595 !net::URLRequest::IsHandledURL(url)) { 596 return true; // This URL request is destined for ShellExecute. 597 } 598 599 { 600 base::AutoLock lock(lock_); 601 602 SecurityStateMap::iterator state = security_state_.find(child_id); 603 if (state == security_state_.end()) 604 return false; 605 606 // Otherwise, we consult the child process's security state to see if it is 607 // allowed to request the URL. 608 return state->second->CanRequestURL(url); 609 } 610} 611 612bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id, 613 const base::FilePath& file) { 614 return HasPermissionsForFile(child_id, file, kReadFilePermissions); 615} 616 617bool ChildProcessSecurityPolicyImpl::CanWriteFile(int child_id, 618 const base::FilePath& file) { 619 return HasPermissionsForFile(child_id, file, kWriteFilePermissions); 620} 621 622bool ChildProcessSecurityPolicyImpl::CanCreateFile(int child_id, 623 const base::FilePath& file) { 624 return HasPermissionsForFile(child_id, file, kCreateFilePermissions); 625} 626 627bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFile( 628 int child_id, 629 const base::FilePath& file) { 630 return HasPermissionsForFile(child_id, file, kCreateReadWriteFilePermissions); 631} 632 633bool ChildProcessSecurityPolicyImpl::CanReadDirectory( 634 int child_id, const base::FilePath& directory) { 635 return HasPermissionsForFile(child_id, 636 directory, 637 kEnumerateDirectoryPermissions); 638} 639 640bool ChildProcessSecurityPolicyImpl::CanReadFileSystem( 641 int child_id, const std::string& filesystem_id) { 642 return HasPermissionsForFileSystem(child_id, 643 filesystem_id, 644 kReadFilePermissions); 645} 646 647bool ChildProcessSecurityPolicyImpl::CanReadWriteFileSystem( 648 int child_id, const std::string& filesystem_id) { 649 return HasPermissionsForFileSystem(child_id, 650 filesystem_id, 651 kReadFilePermissions | 652 kWriteFilePermissions); 653} 654 655bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystem( 656 int child_id, const std::string& filesystem_id) { 657 // TODO(tommycli): These granted permissions a bit too broad, but not abused. 658 // We are fixing in http://crbug.com/262142 and associated CL. 659 return HasPermissionsForFileSystem(child_id, 660 filesystem_id, 661 kCreateFilePermissions); 662} 663 664bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile( 665 int child_id, const base::FilePath& file, int permissions) { 666 base::AutoLock lock(lock_); 667 bool result = ChildProcessHasPermissionsForFile(child_id, file, permissions); 668 if (!result) { 669 // If this is a worker thread that has no access to a given file, 670 // let's check that its renderer process has access to that file instead. 671 WorkerToMainProcessMap::iterator iter = worker_map_.find(child_id); 672 if (iter != worker_map_.end() && iter->second != 0) { 673 result = ChildProcessHasPermissionsForFile(iter->second, 674 file, 675 permissions); 676 } 677 } 678 return result; 679} 680 681bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile( 682 int child_id, const fileapi::FileSystemURL& url, int permissions) { 683 if (!url.is_valid()) 684 return false; 685 686 if (url.path().ReferencesParent()) 687 return false; 688 689 // Any write access is disallowed on the root path. 690 if (fileapi::VirtualPath::IsRootPath(url.path()) && 691 (permissions & ~kReadFilePermissions)) { 692 return false; 693 } 694 695 if (url.mount_type() == fileapi::kFileSystemTypeIsolated) { 696 // When Isolated filesystems is overlayed on top of another filesystem, 697 // its per-filesystem permission overrides the underlying filesystem 698 // permissions). 699 return HasPermissionsForFileSystem( 700 child_id, url.mount_filesystem_id(), permissions); 701 } 702 703 FileSystemPermissionPolicyMap::iterator found = 704 file_system_policy_map_.find(url.type()); 705 if (found == file_system_policy_map_.end()) 706 return false; 707 708 if ((found->second & fileapi::FILE_PERMISSION_READ_ONLY) && 709 permissions & ~kReadFilePermissions) { 710 return false; 711 } 712 713 if (found->second & fileapi::FILE_PERMISSION_USE_FILE_PERMISSION) 714 return HasPermissionsForFile(child_id, url.path(), permissions); 715 716 if (found->second & fileapi::FILE_PERMISSION_SANDBOX) 717 return true; 718 719 return false; 720} 721 722bool ChildProcessSecurityPolicyImpl::CanReadFileSystemFile( 723 int child_id, 724 const fileapi::FileSystemURL& url) { 725 return HasPermissionsForFileSystemFile(child_id, url, kReadFilePermissions); 726} 727 728bool ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile( 729 int child_id, 730 const fileapi::FileSystemURL& url) { 731 return HasPermissionsForFileSystemFile(child_id, url, kWriteFilePermissions); 732} 733 734bool ChildProcessSecurityPolicyImpl::CanCreateFileSystemFile( 735 int child_id, 736 const fileapi::FileSystemURL& url) { 737 return HasPermissionsForFileSystemFile(child_id, url, kCreateFilePermissions); 738} 739 740bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFileSystemFile( 741 int child_id, 742 const fileapi::FileSystemURL& url) { 743 return HasPermissionsForFileSystemFile(child_id, url, 744 kCreateReadWriteFilePermissions); 745} 746 747bool ChildProcessSecurityPolicyImpl::HasWebUIBindings(int child_id) { 748 base::AutoLock lock(lock_); 749 750 SecurityStateMap::iterator state = security_state_.find(child_id); 751 if (state == security_state_.end()) 752 return false; 753 754 return state->second->has_web_ui_bindings(); 755} 756 757bool ChildProcessSecurityPolicyImpl::CanReadRawCookies(int child_id) { 758 base::AutoLock lock(lock_); 759 760 SecurityStateMap::iterator state = security_state_.find(child_id); 761 if (state == security_state_.end()) 762 return false; 763 764 return state->second->can_read_raw_cookies(); 765} 766 767void ChildProcessSecurityPolicyImpl::AddChild(int child_id) { 768 if (security_state_.count(child_id) != 0) { 769 NOTREACHED() << "Add child process at most once."; 770 return; 771 } 772 773 security_state_[child_id] = new SecurityState(); 774} 775 776bool ChildProcessSecurityPolicyImpl::ChildProcessHasPermissionsForFile( 777 int child_id, const base::FilePath& file, int permissions) { 778 SecurityStateMap::iterator state = security_state_.find(child_id); 779 if (state == security_state_.end()) 780 return false; 781 return state->second->HasPermissionsForFile(file, permissions); 782} 783 784bool ChildProcessSecurityPolicyImpl::CanAccessCookiesForOrigin( 785 int child_id, const GURL& gurl) { 786 base::AutoLock lock(lock_); 787 SecurityStateMap::iterator state = security_state_.find(child_id); 788 if (state == security_state_.end()) 789 return false; 790 return state->second->CanAccessCookiesForOrigin(gurl); 791} 792 793bool ChildProcessSecurityPolicyImpl::CanSendCookiesForOrigin(int child_id, 794 const GURL& gurl) { 795 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) { 796 if (iter.GetData().process_type == child_id) { 797 if (iter.GetData().process_type == PROCESS_TYPE_PLUGIN) { 798 // NPAPI plugin processes are unsandboxed and so are trusted. Plugins 799 // can make request to any origin. 800 return true; 801 } 802 break; 803 } 804 } 805 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->CanSendCookiesForOrigin(gurl); 811} 812 813void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id, 814 const GURL& gurl) { 815 // "gurl" can be currently empty in some cases, such as file://blah. 816 DCHECK(SiteInstanceImpl::GetSiteForURL(NULL, gurl) == gurl); 817 base::AutoLock lock(lock_); 818 SecurityStateMap::iterator state = security_state_.find(child_id); 819 DCHECK(state != security_state_.end()); 820 state->second->LockToOrigin(gurl); 821} 822 823void ChildProcessSecurityPolicyImpl::GrantPermissionsForFileSystem( 824 int child_id, 825 const std::string& filesystem_id, 826 int permission) { 827 base::AutoLock lock(lock_); 828 829 SecurityStateMap::iterator state = security_state_.find(child_id); 830 if (state == security_state_.end()) 831 return; 832 state->second->GrantPermissionsForFileSystem(filesystem_id, permission); 833} 834 835bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystem( 836 int child_id, 837 const std::string& filesystem_id, 838 int permission) { 839 base::AutoLock lock(lock_); 840 841 SecurityStateMap::iterator state = security_state_.find(child_id); 842 if (state == security_state_.end()) 843 return false; 844 return state->second->HasPermissionsForFileSystem(filesystem_id, permission); 845} 846 847void ChildProcessSecurityPolicyImpl::RegisterFileSystemPermissionPolicy( 848 fileapi::FileSystemType type, 849 int policy) { 850 base::AutoLock lock(lock_); 851 file_system_policy_map_[type] = policy; 852} 853 854bool ChildProcessSecurityPolicyImpl::CanSendMIDISysExMessage(int child_id) { 855 base::AutoLock lock(lock_); 856 857 SecurityStateMap::iterator state = security_state_.find(child_id); 858 if (state == security_state_.end()) 859 return false; 860 861 return state->second->can_send_midi_sysex(); 862} 863 864} // namespace content 865