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