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/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