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