Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / content / browser / child_process_security_policy_impl.cc
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(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(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
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(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(kChromeUIScheme);
549
550   // Web UI pages can contain links to file:// URLs.
551   state->second->GrantScheme(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