Home | History | Annotate | Download | only in browser
      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