OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/child_process_security_policy_impl.h" | 5 #include "content/browser/child_process_security_policy_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
195 void RevokeReadRawCookies() { | 195 void RevokeReadRawCookies() { |
196 can_read_raw_cookies_ = false; | 196 can_read_raw_cookies_ = false; |
197 } | 197 } |
198 | 198 |
199 void GrantPermissionForMidiSysEx() { | 199 void GrantPermissionForMidiSysEx() { |
200 can_send_midi_sysex_ = true; | 200 can_send_midi_sysex_ = true; |
201 } | 201 } |
202 | 202 |
203 // Determine whether permission has been granted to commit |url|. | 203 // Determine whether permission has been granted to commit |url|. |
204 bool CanCommitURL(const GURL& url) { | 204 bool CanCommitURL(const GURL& url) { |
205 DCHECK(!url.SchemeIsBlob() && !url.SchemeIsFileSystem()) | |
206 << "inner_url extraction should be done already."; | |
205 // Having permission to a scheme implies permission to all of its URLs. | 207 // Having permission to a scheme implies permission to all of its URLs. |
206 SchemeMap::const_iterator scheme_judgment( | 208 SchemeMap::const_iterator scheme_judgment( |
207 scheme_policy_.find(url.scheme())); | 209 scheme_policy_.find(url.scheme())); |
208 if (scheme_judgment != scheme_policy_.end()) | 210 if (scheme_judgment != scheme_policy_.end()) |
209 return scheme_judgment->second; | 211 return scheme_judgment->second; |
210 | 212 |
211 // Otherwise, check for permission for specific origin. | 213 // Otherwise, check for permission for specific origin. |
212 if (base::ContainsKey(origin_set_, url::Origin(url))) | 214 if (base::ContainsKey(origin_set_, url::Origin(url))) |
213 return true; | 215 return true; |
214 | 216 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
319 DISALLOW_COPY_AND_ASSIGN(SecurityState); | 321 DISALLOW_COPY_AND_ASSIGN(SecurityState); |
320 }; | 322 }; |
321 | 323 |
322 ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() { | 324 ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl() { |
323 // We know about these schemes and believe them to be safe. | 325 // We know about these schemes and believe them to be safe. |
324 RegisterWebSafeScheme(url::kHttpScheme); | 326 RegisterWebSafeScheme(url::kHttpScheme); |
325 RegisterWebSafeScheme(url::kHttpsScheme); | 327 RegisterWebSafeScheme(url::kHttpsScheme); |
326 RegisterWebSafeScheme(url::kFtpScheme); | 328 RegisterWebSafeScheme(url::kFtpScheme); |
327 RegisterWebSafeScheme(url::kDataScheme); | 329 RegisterWebSafeScheme(url::kDataScheme); |
328 RegisterWebSafeScheme("feed"); | 330 RegisterWebSafeScheme("feed"); |
331 | |
332 // TODO(nick): blob: and filesystem: schemes embed other origins, | |
333 // so we should not treat them as web safe. Remove callers of | |
334 // IsWebSafeScheme(), and then eliminate the next two lines. | |
329 RegisterWebSafeScheme(url::kBlobScheme); | 335 RegisterWebSafeScheme(url::kBlobScheme); |
330 RegisterWebSafeScheme(url::kFileSystemScheme); | 336 RegisterWebSafeScheme(url::kFileSystemScheme); |
331 | 337 |
332 // We know about the following pseudo schemes and treat them specially. | 338 // We know about the following pseudo schemes and treat them specially. |
333 RegisterPseudoScheme(url::kAboutScheme); | 339 RegisterPseudoScheme(url::kAboutScheme); |
334 RegisterPseudoScheme(url::kJavaScriptScheme); | 340 RegisterPseudoScheme(url::kJavaScriptScheme); |
335 RegisterPseudoScheme(kViewSourceScheme); | 341 RegisterPseudoScheme(kViewSourceScheme); |
336 RegisterPseudoScheme(kHttpSuboriginScheme); | 342 RegisterPseudoScheme(kHttpSuboriginScheme); |
337 RegisterPseudoScheme(kHttpsSuboriginScheme); | 343 RegisterPseudoScheme(kHttpsSuboriginScheme); |
338 } | 344 } |
339 | 345 |
340 ChildProcessSecurityPolicyImpl::~ChildProcessSecurityPolicyImpl() { | 346 ChildProcessSecurityPolicyImpl::~ChildProcessSecurityPolicyImpl() { |
341 web_safe_schemes_.clear(); | 347 schemes_okay_to_request_in_any_process_.clear(); |
348 schemes_okay_to_commit_in_any_process_.clear(); | |
342 pseudo_schemes_.clear(); | 349 pseudo_schemes_.clear(); |
343 security_state_.clear(); | 350 security_state_.clear(); |
344 } | 351 } |
345 | 352 |
346 // static | 353 // static |
347 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { | 354 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { |
348 return ChildProcessSecurityPolicyImpl::GetInstance(); | 355 return ChildProcessSecurityPolicyImpl::GetInstance(); |
349 } | 356 } |
350 | 357 |
351 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() { | 358 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() { |
(...skipping 14 matching lines...) Expand all Loading... | |
366 | 373 |
367 void ChildProcessSecurityPolicyImpl::Remove(int child_id) { | 374 void ChildProcessSecurityPolicyImpl::Remove(int child_id) { |
368 base::AutoLock lock(lock_); | 375 base::AutoLock lock(lock_); |
369 security_state_.erase(child_id); | 376 security_state_.erase(child_id); |
370 worker_map_.erase(child_id); | 377 worker_map_.erase(child_id); |
371 } | 378 } |
372 | 379 |
373 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme( | 380 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme( |
374 const std::string& scheme) { | 381 const std::string& scheme) { |
375 base::AutoLock lock(lock_); | 382 base::AutoLock lock(lock_); |
376 DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) << "Add schemes at most once."; | 383 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme)) |
384 << "Add schemes at most once."; | |
377 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) | 385 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) |
378 << "Web-safe implies not pseudo."; | 386 << "Web-safe implies not pseudo."; |
379 | 387 |
380 web_safe_schemes_.insert(scheme); | 388 schemes_okay_to_request_in_any_process_.insert(scheme); |
389 schemes_okay_to_commit_in_any_process_.insert(scheme); | |
390 } | |
391 | |
392 void ChildProcessSecurityPolicyImpl::RegisterWebSafeIsolatedScheme( | |
393 const std::string& scheme) { | |
394 base::AutoLock lock(lock_); | |
395 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme)) | |
396 << "Add schemes at most once."; | |
397 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) | |
398 << "Web-safe implies not pseudo."; | |
399 | |
400 schemes_okay_to_request_in_any_process_.insert(scheme); | |
381 } | 401 } |
382 | 402 |
383 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme( | 403 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme( |
384 const std::string& scheme) { | 404 const std::string& scheme) { |
385 base::AutoLock lock(lock_); | 405 base::AutoLock lock(lock_); |
386 | 406 |
387 return base::ContainsKey(web_safe_schemes_, scheme); | 407 return base::ContainsKey(schemes_okay_to_request_in_any_process_, scheme); |
388 } | 408 } |
389 | 409 |
390 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme( | 410 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme( |
391 const std::string& scheme) { | 411 const std::string& scheme) { |
392 base::AutoLock lock(lock_); | 412 base::AutoLock lock(lock_); |
393 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once."; | 413 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once."; |
394 DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) | 414 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme)) |
415 << "Pseudo implies not web-safe."; | |
416 DCHECK_EQ(0U, schemes_okay_to_commit_in_any_process_.count(scheme)) | |
395 << "Pseudo implies not web-safe."; | 417 << "Pseudo implies not web-safe."; |
396 | 418 |
397 pseudo_schemes_.insert(scheme); | 419 pseudo_schemes_.insert(scheme); |
398 } | 420 } |
399 | 421 |
400 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme( | 422 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme( |
401 const std::string& scheme) { | 423 const std::string& scheme) { |
402 base::AutoLock lock(lock_); | 424 base::AutoLock lock(lock_); |
403 | 425 |
404 return base::ContainsKey(pseudo_schemes_, scheme); | 426 return base::ContainsKey(pseudo_schemes_, scheme); |
405 } | 427 } |
406 | 428 |
407 void ChildProcessSecurityPolicyImpl::GrantRequestURL( | 429 void ChildProcessSecurityPolicyImpl::GrantRequestURL( |
408 int child_id, const GURL& url) { | 430 int child_id, const GURL& url) { |
409 | 431 |
410 if (!url.is_valid()) | 432 if (!url.is_valid()) |
411 return; // Can't grant the capability to request invalid URLs. | 433 return; // Can't grant the capability to request invalid URLs. |
412 | 434 |
413 if (IsWebSafeScheme(url.scheme())) | 435 if (IsWebSafeScheme(url.scheme())) |
414 return; // The scheme has already been whitelisted for every child process. | 436 return; // The scheme has already been whitelisted for every child process. |
415 | 437 |
416 if (IsPseudoScheme(url.scheme())) { | 438 if (IsPseudoScheme(url.scheme())) { |
417 return; // Can't grant the capability to request pseudo schemes. | 439 return; // Can't grant the capability to request pseudo schemes. |
418 } | 440 } |
419 | 441 |
442 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) { | |
443 return; // Don't grant blanket access to blob: or filesystem: schemes. | |
444 } | |
445 | |
420 { | 446 { |
421 base::AutoLock lock(lock_); | 447 base::AutoLock lock(lock_); |
422 SecurityStateMap::iterator state = security_state_.find(child_id); | 448 SecurityStateMap::iterator state = security_state_.find(child_id); |
423 if (state == security_state_.end()) | 449 if (state == security_state_.end()) |
424 return; | 450 return; |
425 | 451 |
426 // When the child process has been commanded to request this scheme, | 452 // When the child process has been commanded to request this scheme, |
427 // we grant it the capability to request all URLs of that scheme. | 453 // we grant it the capability to request all URLs of that scheme. |
428 state->second->GrantScheme(url.scheme()); | 454 state->second->GrantScheme(url.scheme()); |
429 } | 455 } |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
599 // Every child process can request <about:blank>. | 625 // Every child process can request <about:blank>. |
600 if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL)) | 626 if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL)) |
601 return true; | 627 return true; |
602 // URLs like <about:version>, <about:crash>, <view-source:...> shouldn't be | 628 // URLs like <about:version>, <about:crash>, <view-source:...> shouldn't be |
603 // requestable by any child process. Also, this case covers | 629 // requestable by any child process. Also, this case covers |
604 // <javascript:...>, which should be handled internally by the process and | 630 // <javascript:...>, which should be handled internally by the process and |
605 // not kicked up to the browser. | 631 // not kicked up to the browser. |
606 return false; | 632 return false; |
607 } | 633 } |
608 | 634 |
609 if (IsMalformedBlobUrl(url)) | 635 // Blob and filesystem URLs require special treatment, since they embed an |
610 return false; | 636 // inner origin. |
637 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) { | |
638 if (IsMalformedBlobUrl(url)) | |
639 return false; | |
640 | |
641 url::Origin origin(url); | |
642 return origin.unique() || IsWebSafeScheme(origin.scheme()) || | |
643 CanCommitURL(child_id, GURL(origin.Serialize())); | |
644 } | |
645 | |
646 if (IsWebSafeScheme(url.scheme())) | |
647 return true; | |
611 | 648 |
612 // If the process can commit the URL, it can request it. | 649 // If the process can commit the URL, it can request it. |
613 if (CanCommitURL(child_id, url)) | 650 if (CanCommitURL(child_id, url)) |
614 return true; | 651 return true; |
615 | 652 |
616 // Also allow URLs destined for ShellExecute and not the browser itself. | 653 // Also allow URLs destined for ShellExecute and not the browser itself. |
617 return !GetContentClient()->browser()->IsHandledURL(url) && | 654 return !GetContentClient()->browser()->IsHandledURL(url) && |
618 !net::URLRequest::IsHandledURL(url); | 655 !net::URLRequest::IsHandledURL(url); |
619 } | 656 } |
620 | 657 |
621 bool ChildProcessSecurityPolicyImpl::CanCommitURL(int child_id, | 658 bool ChildProcessSecurityPolicyImpl::CanCommitURL(int child_id, |
622 const GURL& url) { | 659 const GURL& url) { |
623 if (!url.is_valid()) | 660 if (!url.is_valid()) |
624 return false; // Can't commit invalid URLs. | 661 return false; // Can't commit invalid URLs. |
625 | 662 |
626 // Of all the pseudo schemes, only about:blank is allowed to commit. | 663 // Of all the pseudo schemes, only about:blank is allowed to commit. |
627 if (IsPseudoScheme(url.scheme())) | 664 if (IsPseudoScheme(url.scheme())) |
628 return base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL); | 665 return base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL); |
629 | 666 |
630 if (IsMalformedBlobUrl(url)) | 667 // Blob and filesystem URLs require special treatment; validate the inner |
631 return false; | 668 // origin they embed. |
669 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) { | |
670 if (IsMalformedBlobUrl(url)) | |
671 return false; | |
632 | 672 |
633 // TODO(creis): Tighten this for Site Isolation, so that a URL from a site | 673 url::Origin origin(url); |
634 // that is isolated can only be committed in a process dedicated to that site. | 674 return origin.unique() || CanCommitURL(child_id, GURL(origin.Serialize())); |
635 // CanRequestURL should still allow all web-safe schemes. See | 675 } |
636 // https://crbug.com/515309. | |
Charlie Reis
2016/09/28 22:07:16
Can we keep this TODO, or is there a reason that i
ncarter (slow)
2016/09/29 21:01:45
I updated the TODO.
| |
637 if (IsWebSafeScheme(url.scheme())) | |
638 return true; // The scheme has been white-listed for every child process. | |
639 | 676 |
640 { | 677 { |
641 base::AutoLock lock(lock_); | 678 base::AutoLock lock(lock_); |
642 | 679 |
680 // Most schemes can commit in any process. Note that we check | |
681 // schemes_okay_to_commit_in_any_process_ here, which is stricter than | |
682 // IsWebSafeScheme(). | |
683 if (base::ContainsKey(schemes_okay_to_commit_in_any_process_, url.scheme())) | |
684 return true; | |
685 | |
643 SecurityStateMap::iterator state = security_state_.find(child_id); | 686 SecurityStateMap::iterator state = security_state_.find(child_id); |
644 if (state == security_state_.end()) | 687 if (state == security_state_.end()) |
645 return false; | 688 return false; |
646 | 689 |
647 // Otherwise, we consult the child process's security state to see if it is | 690 // Otherwise, we consult the child process's security state to see if it is |
648 // allowed to commit the URL. | 691 // allowed to commit the URL. |
649 return state->second->CanCommitURL(url); | 692 return state->second->CanCommitURL(url); |
650 } | 693 } |
651 } | 694 } |
652 | 695 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
899 base::AutoLock lock(lock_); | 942 base::AutoLock lock(lock_); |
900 | 943 |
901 SecurityStateMap::iterator state = security_state_.find(child_id); | 944 SecurityStateMap::iterator state = security_state_.find(child_id); |
902 if (state == security_state_.end()) | 945 if (state == security_state_.end()) |
903 return false; | 946 return false; |
904 | 947 |
905 return state->second->can_send_midi_sysex(); | 948 return state->second->can_send_midi_sysex(); |
906 } | 949 } |
907 | 950 |
908 } // namespace content | 951 } // namespace content |
OLD | NEW |