child_process_security_policy_impl.cc revision 010d83a9304c5a91596085d917d248abff47903a
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/filename_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
34// Used internally only. These bit positions have no relationship to any
35// underlying OS and can be changed to accommodate finer-grained permissions.
36enum 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.
49enum 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.
71class 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(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
309ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() {
310  // We know about these schemes and believe them to be safe.
311  RegisterWebSafeScheme(url::kHttpScheme);
312  RegisterWebSafeScheme(url::kHttpsScheme);
313  RegisterWebSafeScheme(kFtpScheme);
314  RegisterWebSafeScheme(kDataScheme);
315  RegisterWebSafeScheme("feed");
316  RegisterWebSafeScheme(kBlobScheme);
317  RegisterWebSafeScheme(kFileSystemScheme);
318
319  // We know about the following pseudo schemes and treat them specially.
320  RegisterPseudoScheme(kAboutScheme);
321  RegisterPseudoScheme(kJavaScriptScheme);
322  RegisterPseudoScheme(kViewSourceScheme);
323}
324
325ChildProcessSecurityPolicyImpl::~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
334ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() {
335  return ChildProcessSecurityPolicyImpl::GetInstance();
336}
337
338ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() {
339  return Singleton<ChildProcessSecurityPolicyImpl>::get();
340}
341
342void ChildProcessSecurityPolicyImpl::Add(int child_id) {
343  base::AutoLock lock(lock_);
344  AddChild(child_id);
345}
346
347void 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
354void 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
365void 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
375bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme(
376    const std::string& scheme) {
377  base::AutoLock lock(lock_);
378
379  return ContainsKey(web_safe_schemes_, scheme);
380}
381
382void 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
392bool ChildProcessSecurityPolicyImpl::IsPseudoScheme(
393    const std::string& scheme) {
394  base::AutoLock lock(lock_);
395
396  return ContainsKey(pseudo_schemes_, scheme);
397}
398
399void 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
434void ChildProcessSecurityPolicyImpl::GrantRequestSpecificFileURL(
435    int child_id,
436    const GURL& url) {
437  if (!url.SchemeIs(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
454void ChildProcessSecurityPolicyImpl::GrantReadFile(int child_id,
455                                                   const base::FilePath& file) {
456  GrantPermissionsForFile(child_id, file, READ_FILE_GRANT);
457}
458
459void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFile(
460    int child_id, const base::FilePath& file) {
461  GrantPermissionsForFile(child_id, file, CREATE_READ_WRITE_FILE_GRANT);
462}
463
464void ChildProcessSecurityPolicyImpl::GrantCopyInto(int child_id,
465                                                   const base::FilePath& dir) {
466  GrantPermissionsForFile(child_id, dir, COPY_INTO_FILE_GRANT);
467}
468
469void ChildProcessSecurityPolicyImpl::GrantDeleteFrom(
470    int child_id, const base::FilePath& dir) {
471  GrantPermissionsForFile(child_id, dir, DELETE_FILE_GRANT);
472}
473
474void ChildProcessSecurityPolicyImpl::GrantPermissionsForFile(
475    int child_id, const base::FilePath& file, int permissions) {
476  base::AutoLock lock(lock_);
477
478  SecurityStateMap::iterator state = security_state_.find(child_id);
479  if (state == security_state_.end())
480    return;
481
482  state->second->GrantPermissionsForFile(file, permissions);
483}
484
485void ChildProcessSecurityPolicyImpl::RevokeAllPermissionsForFile(
486    int child_id, const base::FilePath& file) {
487  base::AutoLock lock(lock_);
488
489  SecurityStateMap::iterator state = security_state_.find(child_id);
490  if (state == security_state_.end())
491    return;
492
493  state->second->RevokeAllPermissionsForFile(file);
494}
495
496void ChildProcessSecurityPolicyImpl::GrantReadFileSystem(
497    int child_id, const std::string& filesystem_id) {
498  GrantPermissionsForFileSystem(child_id, filesystem_id, READ_FILE_GRANT);
499}
500
501void ChildProcessSecurityPolicyImpl::GrantWriteFileSystem(
502    int child_id, const std::string& filesystem_id) {
503  GrantPermissionsForFileSystem(child_id, filesystem_id, WRITE_FILE_GRANT);
504}
505
506void ChildProcessSecurityPolicyImpl::GrantCreateFileForFileSystem(
507    int child_id, const std::string& filesystem_id) {
508  GrantPermissionsForFileSystem(child_id, filesystem_id, CREATE_NEW_FILE_GRANT);
509}
510
511void ChildProcessSecurityPolicyImpl::GrantCreateReadWriteFileSystem(
512    int child_id, const std::string& filesystem_id) {
513  GrantPermissionsForFileSystem(
514      child_id, filesystem_id, CREATE_READ_WRITE_FILE_GRANT);
515}
516
517void ChildProcessSecurityPolicyImpl::GrantCopyIntoFileSystem(
518    int child_id, const std::string& filesystem_id) {
519  GrantPermissionsForFileSystem(child_id, filesystem_id, COPY_INTO_FILE_GRANT);
520}
521
522void ChildProcessSecurityPolicyImpl::GrantDeleteFromFileSystem(
523    int child_id, const std::string& filesystem_id) {
524  GrantPermissionsForFileSystem(child_id, filesystem_id, DELETE_FILE_GRANT);
525}
526
527void ChildProcessSecurityPolicyImpl::GrantSendMidiSysExMessage(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->GrantPermissionForMidiSysEx();
535}
536
537void ChildProcessSecurityPolicyImpl::GrantScheme(int child_id,
538                                                 const std::string& scheme) {
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->GrantScheme(scheme);
546}
547
548void ChildProcessSecurityPolicyImpl::GrantWebUIBindings(int child_id) {
549  base::AutoLock lock(lock_);
550
551  SecurityStateMap::iterator state = security_state_.find(child_id);
552  if (state == security_state_.end())
553    return;
554
555  state->second->GrantBindings(BINDINGS_POLICY_WEB_UI);
556
557  // Web UI bindings need the ability to request chrome: URLs.
558  state->second->GrantScheme(kChromeUIScheme);
559
560  // Web UI pages can contain links to file:// URLs.
561  state->second->GrantScheme(kFileScheme);
562}
563
564void ChildProcessSecurityPolicyImpl::GrantReadRawCookies(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->GrantReadRawCookies();
572}
573
574void ChildProcessSecurityPolicyImpl::RevokeReadRawCookies(int child_id) {
575  base::AutoLock lock(lock_);
576
577  SecurityStateMap::iterator state = security_state_.find(child_id);
578  if (state == security_state_.end())
579    return;
580
581  state->second->RevokeReadRawCookies();
582}
583
584bool ChildProcessSecurityPolicyImpl::CanLoadPage(
585    int child_id,
586    const GURL& url,
587    ResourceType::Type resource_type) {
588  // If --site-per-process flag is passed, we should enforce
589  // stronger security restrictions on page navigation.
590  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
591      ResourceType::IsFrame(resource_type)) {
592    // TODO(nasko): Do the proper check for site-per-process, once
593    // out-of-process iframes is ready to go.
594    return true;
595  }
596  return true;
597}
598
599bool ChildProcessSecurityPolicyImpl::CanRequestURL(
600    int child_id, const GURL& url) {
601  if (!url.is_valid())
602    return false;  // Can't request invalid URLs.
603
604  if (IsWebSafeScheme(url.scheme()))
605    return true;  // The scheme has been white-listed for every child process.
606
607  if (IsPseudoScheme(url.scheme())) {
608    // There are a number of special cases for pseudo schemes.
609
610    if (url.SchemeIs(kViewSourceScheme)) {
611      // A view-source URL is allowed if the child process is permitted to
612      // request the embedded URL. Careful to avoid pointless recursion.
613      GURL child_url(url.GetContent());
614      if (child_url.SchemeIs(kViewSourceScheme) &&
615          url.SchemeIs(kViewSourceScheme))
616          return false;
617
618      return CanRequestURL(child_id, child_url);
619    }
620
621    if (LowerCaseEqualsASCII(url.spec(), kAboutBlankURL))
622      return true;  // Every child process can request <about:blank>.
623
624    // URLs like <about:memory> and <about:crash> shouldn't be requestable by
625    // any child process.  Also, this case covers <javascript:...>, which should
626    // be handled internally by the process and not kicked up to the browser.
627    return false;
628  }
629
630  if (!GetContentClient()->browser()->IsHandledURL(url) &&
631      !net::URLRequest::IsHandledURL(url)) {
632    return true;  // This URL request is destined for ShellExecute.
633  }
634
635  {
636    base::AutoLock lock(lock_);
637
638    SecurityStateMap::iterator state = security_state_.find(child_id);
639    if (state == security_state_.end())
640      return false;
641
642    // Otherwise, we consult the child process's security state to see if it is
643    // allowed to request the URL.
644    return state->second->CanRequestURL(url);
645  }
646}
647
648bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id,
649                                                 const base::FilePath& file) {
650  return HasPermissionsForFile(child_id, file, READ_FILE_GRANT);
651}
652
653bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFile(
654    int child_id,
655    const base::FilePath& file) {
656  return HasPermissionsForFile(child_id, file, CREATE_READ_WRITE_FILE_GRANT);
657}
658
659bool ChildProcessSecurityPolicyImpl::CanReadFileSystem(
660    int child_id, const std::string& filesystem_id) {
661  return HasPermissionsForFileSystem(child_id, filesystem_id, READ_FILE_GRANT);
662}
663
664bool ChildProcessSecurityPolicyImpl::CanReadWriteFileSystem(
665    int child_id, const std::string& filesystem_id) {
666  return HasPermissionsForFileSystem(child_id, filesystem_id,
667                                     READ_FILE_GRANT | WRITE_FILE_GRANT);
668}
669
670bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystem(
671    int child_id, const std::string& filesystem_id) {
672  return HasPermissionsForFileSystem(child_id, filesystem_id,
673                                     COPY_INTO_FILE_GRANT);
674}
675
676bool ChildProcessSecurityPolicyImpl::CanDeleteFromFileSystem(
677    int child_id, const std::string& filesystem_id) {
678  return HasPermissionsForFileSystem(child_id, filesystem_id,
679                                     DELETE_FILE_GRANT);
680}
681
682bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile(
683    int child_id, const base::FilePath& file, int permissions) {
684  base::AutoLock lock(lock_);
685  bool result = ChildProcessHasPermissionsForFile(child_id, file, permissions);
686  if (!result) {
687    // If this is a worker thread that has no access to a given file,
688    // let's check that its renderer process has access to that file instead.
689    WorkerToMainProcessMap::iterator iter = worker_map_.find(child_id);
690    if (iter != worker_map_.end() && iter->second != 0) {
691      result = ChildProcessHasPermissionsForFile(iter->second,
692                                                 file,
693                                                 permissions);
694    }
695  }
696  return result;
697}
698
699bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
700    int child_id, const fileapi::FileSystemURL& url, int permissions) {
701  if (!url.is_valid())
702    return false;
703
704  if (url.path().ReferencesParent())
705    return false;
706
707  // Any write access is disallowed on the root path.
708  if (fileapi::VirtualPath::IsRootPath(url.path()) &&
709      (permissions & ~READ_FILE_GRANT)) {
710    return false;
711  }
712
713  if (url.mount_type() == fileapi::kFileSystemTypeIsolated) {
714    // When Isolated filesystems is overlayed on top of another filesystem,
715    // its per-filesystem permission overrides the underlying filesystem
716    // permissions).
717    return HasPermissionsForFileSystem(
718        child_id, url.mount_filesystem_id(), permissions);
719  }
720
721  FileSystemPermissionPolicyMap::iterator found =
722      file_system_policy_map_.find(url.type());
723  if (found == file_system_policy_map_.end())
724    return false;
725
726  if ((found->second & fileapi::FILE_PERMISSION_READ_ONLY) &&
727      permissions & ~READ_FILE_GRANT) {
728    return false;
729  }
730
731  if (found->second & fileapi::FILE_PERMISSION_USE_FILE_PERMISSION)
732    return HasPermissionsForFile(child_id, url.path(), permissions);
733
734  if (found->second & fileapi::FILE_PERMISSION_SANDBOX)
735    return true;
736
737  return false;
738}
739
740bool ChildProcessSecurityPolicyImpl::CanReadFileSystemFile(
741    int child_id,
742    const fileapi::FileSystemURL& url) {
743  return HasPermissionsForFileSystemFile(child_id, url, READ_FILE_GRANT);
744}
745
746bool ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile(
747    int child_id,
748    const fileapi::FileSystemURL& url) {
749  return HasPermissionsForFileSystemFile(child_id, url, WRITE_FILE_GRANT);
750}
751
752bool ChildProcessSecurityPolicyImpl::CanCreateFileSystemFile(
753    int child_id,
754    const fileapi::FileSystemURL& url) {
755  return HasPermissionsForFileSystemFile(child_id, url, CREATE_NEW_FILE_GRANT);
756}
757
758bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFileSystemFile(
759    int child_id,
760    const fileapi::FileSystemURL& url) {
761  return HasPermissionsForFileSystemFile(child_id, url,
762                                         CREATE_READ_WRITE_FILE_GRANT);
763}
764
765bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystemFile(
766    int child_id,
767    const fileapi::FileSystemURL& url) {
768  return HasPermissionsForFileSystemFile(child_id, url, COPY_INTO_FILE_GRANT);
769}
770
771bool ChildProcessSecurityPolicyImpl::CanDeleteFileSystemFile(
772    int child_id,
773    const fileapi::FileSystemURL& url) {
774  return HasPermissionsForFileSystemFile(child_id, url, DELETE_FILE_GRANT);
775}
776
777bool ChildProcessSecurityPolicyImpl::HasWebUIBindings(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->has_web_ui_bindings();
785}
786
787bool ChildProcessSecurityPolicyImpl::CanReadRawCookies(int child_id) {
788  base::AutoLock lock(lock_);
789
790  SecurityStateMap::iterator state = security_state_.find(child_id);
791  if (state == security_state_.end())
792    return false;
793
794  return state->second->can_read_raw_cookies();
795}
796
797void ChildProcessSecurityPolicyImpl::AddChild(int child_id) {
798  if (security_state_.count(child_id) != 0) {
799    NOTREACHED() << "Add child process at most once.";
800    return;
801  }
802
803  security_state_[child_id] = new SecurityState();
804}
805
806bool ChildProcessSecurityPolicyImpl::ChildProcessHasPermissionsForFile(
807    int child_id, const base::FilePath& file, int permissions) {
808  SecurityStateMap::iterator state = security_state_.find(child_id);
809  if (state == security_state_.end())
810    return false;
811  return state->second->HasPermissionsForFile(file, permissions);
812}
813
814bool ChildProcessSecurityPolicyImpl::CanAccessCookiesForOrigin(
815    int child_id, const GURL& gurl) {
816  base::AutoLock lock(lock_);
817  SecurityStateMap::iterator state = security_state_.find(child_id);
818  if (state == security_state_.end())
819    return false;
820  return state->second->CanAccessCookiesForOrigin(gurl);
821}
822
823bool ChildProcessSecurityPolicyImpl::CanSendCookiesForOrigin(int child_id,
824                                                             const GURL& gurl) {
825  for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
826    if (iter.GetData().id == child_id) {
827      if (iter.GetData().process_type == PROCESS_TYPE_PLUGIN) {
828        // NPAPI plugin processes are unsandboxed and so are trusted. Plugins
829        // can make request to any origin.
830        return true;
831      }
832      break;
833    }
834  }
835
836  base::AutoLock lock(lock_);
837  SecurityStateMap::iterator state = security_state_.find(child_id);
838  if (state == security_state_.end())
839    return false;
840  return state->second->CanSendCookiesForOrigin(gurl);
841}
842
843void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id,
844                                                  const GURL& gurl) {
845  // "gurl" can be currently empty in some cases, such as file://blah.
846  DCHECK(SiteInstanceImpl::GetSiteForURL(NULL, gurl) == gurl);
847  base::AutoLock lock(lock_);
848  SecurityStateMap::iterator state = security_state_.find(child_id);
849  DCHECK(state != security_state_.end());
850  state->second->LockToOrigin(gurl);
851}
852
853void ChildProcessSecurityPolicyImpl::GrantPermissionsForFileSystem(
854    int child_id,
855    const std::string& filesystem_id,
856    int permission) {
857  base::AutoLock lock(lock_);
858
859  SecurityStateMap::iterator state = security_state_.find(child_id);
860  if (state == security_state_.end())
861    return;
862  state->second->GrantPermissionsForFileSystem(filesystem_id, permission);
863}
864
865bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystem(
866    int child_id,
867    const std::string& filesystem_id,
868    int permission) {
869  base::AutoLock lock(lock_);
870
871  SecurityStateMap::iterator state = security_state_.find(child_id);
872  if (state == security_state_.end())
873    return false;
874  return state->second->HasPermissionsForFileSystem(filesystem_id, permission);
875}
876
877void ChildProcessSecurityPolicyImpl::RegisterFileSystemPermissionPolicy(
878    fileapi::FileSystemType type,
879    int policy) {
880  base::AutoLock lock(lock_);
881  file_system_policy_map_[type] = policy;
882}
883
884bool ChildProcessSecurityPolicyImpl::CanSendMidiSysExMessage(int child_id) {
885  base::AutoLock lock(lock_);
886
887  SecurityStateMap::iterator state = security_state_.find(child_id);
888  if (state == security_state_.end())
889    return false;
890
891  return state->second->can_send_midi_sysex();
892}
893
894}  // namespace content
895