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