Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(450)

Side by Side Diff: content/browser/child_process_security_policy_impl.cc

Issue 2364633004: Lock down the registration of blob:chrome-extension:// URLs (Closed)
Patch Set: Phrasing. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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.
Charlie Reis 2016/09/29 21:39:37 Let's list https://crbug.com/651534 here, too.
ncarter (slow) 2016/09/29 22:04:02 Done.
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();
342 pseudo_schemes_.clear();
343 security_state_.clear();
344 } 347 }
345 348
346 // static 349 // static
347 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() { 350 ChildProcessSecurityPolicy* ChildProcessSecurityPolicy::GetInstance() {
348 return ChildProcessSecurityPolicyImpl::GetInstance(); 351 return ChildProcessSecurityPolicyImpl::GetInstance();
349 } 352 }
350 353
351 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() { 354 ChildProcessSecurityPolicyImpl* ChildProcessSecurityPolicyImpl::GetInstance() {
352 return base::Singleton<ChildProcessSecurityPolicyImpl>::get(); 355 return base::Singleton<ChildProcessSecurityPolicyImpl>::get();
353 } 356 }
(...skipping 12 matching lines...) Expand all
366 369
367 void ChildProcessSecurityPolicyImpl::Remove(int child_id) { 370 void ChildProcessSecurityPolicyImpl::Remove(int child_id) {
368 base::AutoLock lock(lock_); 371 base::AutoLock lock(lock_);
369 security_state_.erase(child_id); 372 security_state_.erase(child_id);
370 worker_map_.erase(child_id); 373 worker_map_.erase(child_id);
371 } 374 }
372 375
373 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme( 376 void ChildProcessSecurityPolicyImpl::RegisterWebSafeScheme(
374 const std::string& scheme) { 377 const std::string& scheme) {
375 base::AutoLock lock(lock_); 378 base::AutoLock lock(lock_);
376 DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) << "Add schemes at most once."; 379 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme))
380 << "Add schemes at most once.";
377 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) 381 DCHECK_EQ(0U, pseudo_schemes_.count(scheme))
378 << "Web-safe implies not pseudo."; 382 << "Web-safe implies not pseudo.";
379 383
380 web_safe_schemes_.insert(scheme); 384 schemes_okay_to_request_in_any_process_.insert(scheme);
385 schemes_okay_to_commit_in_any_process_.insert(scheme);
386 }
387
388 void ChildProcessSecurityPolicyImpl::RegisterWebSafeIsolatedScheme(
389 const std::string& scheme,
390 bool always_allow_in_origin_headers) {
391 base::AutoLock lock(lock_);
392 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme))
393 << "Add schemes at most once.";
394 DCHECK_EQ(0U, pseudo_schemes_.count(scheme))
395 << "Web-safe implies not pseudo.";
396
397 schemes_okay_to_request_in_any_process_.insert(scheme);
398 if (always_allow_in_origin_headers)
399 schemes_okay_to_appear_as_origin_headers_.insert(scheme);
381 } 400 }
382 401
383 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme( 402 bool ChildProcessSecurityPolicyImpl::IsWebSafeScheme(
384 const std::string& scheme) { 403 const std::string& scheme) {
385 base::AutoLock lock(lock_); 404 base::AutoLock lock(lock_);
386 405
387 return base::ContainsKey(web_safe_schemes_, scheme); 406 return base::ContainsKey(schemes_okay_to_request_in_any_process_, scheme);
388 } 407 }
389 408
390 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme( 409 void ChildProcessSecurityPolicyImpl::RegisterPseudoScheme(
391 const std::string& scheme) { 410 const std::string& scheme) {
392 base::AutoLock lock(lock_); 411 base::AutoLock lock(lock_);
393 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once."; 412 DCHECK_EQ(0U, pseudo_schemes_.count(scheme)) << "Add schemes at most once.";
394 DCHECK_EQ(0U, web_safe_schemes_.count(scheme)) 413 DCHECK_EQ(0U, schemes_okay_to_request_in_any_process_.count(scheme))
414 << "Pseudo implies not web-safe.";
415 DCHECK_EQ(0U, schemes_okay_to_commit_in_any_process_.count(scheme))
395 << "Pseudo implies not web-safe."; 416 << "Pseudo implies not web-safe.";
396 417
397 pseudo_schemes_.insert(scheme); 418 pseudo_schemes_.insert(scheme);
398 } 419 }
399 420
400 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme( 421 bool ChildProcessSecurityPolicyImpl::IsPseudoScheme(
401 const std::string& scheme) { 422 const std::string& scheme) {
402 base::AutoLock lock(lock_); 423 base::AutoLock lock(lock_);
403 424
404 return base::ContainsKey(pseudo_schemes_, scheme); 425 return base::ContainsKey(pseudo_schemes_, scheme);
405 } 426 }
406 427
407 void ChildProcessSecurityPolicyImpl::GrantRequestURL( 428 void ChildProcessSecurityPolicyImpl::GrantRequestURL(
408 int child_id, const GURL& url) { 429 int child_id, const GURL& url) {
409 430
410 if (!url.is_valid()) 431 if (!url.is_valid())
411 return; // Can't grant the capability to request invalid URLs. 432 return; // Can't grant the capability to request invalid URLs.
412 433
413 if (IsWebSafeScheme(url.scheme())) 434 if (IsWebSafeScheme(url.scheme()))
414 return; // The scheme has already been whitelisted for every child process. 435 return; // The scheme has already been whitelisted for every child process.
415 436
416 if (IsPseudoScheme(url.scheme())) { 437 if (IsPseudoScheme(url.scheme())) {
417 return; // Can't grant the capability to request pseudo schemes. 438 return; // Can't grant the capability to request pseudo schemes.
418 } 439 }
419 440
441 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) {
442 return; // Don't grant blanket access to blob: or filesystem: schemes.
443 }
444
420 { 445 {
421 base::AutoLock lock(lock_); 446 base::AutoLock lock(lock_);
422 SecurityStateMap::iterator state = security_state_.find(child_id); 447 SecurityStateMap::iterator state = security_state_.find(child_id);
423 if (state == security_state_.end()) 448 if (state == security_state_.end())
424 return; 449 return;
425 450
426 // When the child process has been commanded to request this scheme, 451 // When the child process has been commanded to request this scheme,
427 // we grant it the capability to request all URLs of that scheme. 452 // we grant it the capability to request all URLs of that scheme.
428 state->second->GrantScheme(url.scheme()); 453 state->second->GrantScheme(url.scheme());
429 } 454 }
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 // Every child process can request <about:blank>. 624 // Every child process can request <about:blank>.
600 if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL)) 625 if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL))
601 return true; 626 return true;
602 // URLs like <about:version>, <about:crash>, <view-source:...> shouldn't be 627 // URLs like <about:version>, <about:crash>, <view-source:...> shouldn't be
603 // requestable by any child process. Also, this case covers 628 // requestable by any child process. Also, this case covers
604 // <javascript:...>, which should be handled internally by the process and 629 // <javascript:...>, which should be handled internally by the process and
605 // not kicked up to the browser. 630 // not kicked up to the browser.
606 return false; 631 return false;
607 } 632 }
608 633
609 if (IsMalformedBlobUrl(url)) 634 // Blob and filesystem URLs require special treatment, since they embed an
610 return false; 635 // inner origin.
636 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) {
637 if (IsMalformedBlobUrl(url))
638 return false;
639
640 url::Origin origin(url);
641 return origin.unique() || IsWebSafeScheme(origin.scheme()) ||
642 CanCommitURL(child_id, GURL(origin.Serialize()));
643 }
644
645 if (IsWebSafeScheme(url.scheme()))
646 return true;
611 647
612 // If the process can commit the URL, it can request it. 648 // If the process can commit the URL, it can request it.
613 if (CanCommitURL(child_id, url)) 649 if (CanCommitURL(child_id, url))
614 return true; 650 return true;
615 651
616 // Also allow URLs destined for ShellExecute and not the browser itself. 652 // Also allow URLs destined for ShellExecute and not the browser itself.
617 return !GetContentClient()->browser()->IsHandledURL(url) && 653 return !GetContentClient()->browser()->IsHandledURL(url) &&
618 !net::URLRequest::IsHandledURL(url); 654 !net::URLRequest::IsHandledURL(url);
619 } 655 }
620 656
621 bool ChildProcessSecurityPolicyImpl::CanCommitURL(int child_id, 657 bool ChildProcessSecurityPolicyImpl::CanCommitURL(int child_id,
622 const GURL& url) { 658 const GURL& url) {
623 if (!url.is_valid()) 659 if (!url.is_valid())
624 return false; // Can't commit invalid URLs. 660 return false; // Can't commit invalid URLs.
625 661
626 // Of all the pseudo schemes, only about:blank is allowed to commit. 662 // Of all the pseudo schemes, only about:blank is allowed to commit.
627 if (IsPseudoScheme(url.scheme())) 663 if (IsPseudoScheme(url.scheme()))
628 return base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL); 664 return base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL);
629 665
630 if (IsMalformedBlobUrl(url)) 666 // Blob and filesystem URLs require special treatment; validate the inner
631 return false; 667 // origin they embed.
668 if (url.SchemeIsBlob() || url.SchemeIsFileSystem()) {
669 if (IsMalformedBlobUrl(url))
670 return false;
632 671
633 // TODO(creis): Tighten this for Site Isolation, so that a URL from a site 672 url::Origin origin(url);
634 // that is isolated can only be committed in a process dedicated to that site. 673 return origin.unique() || CanCommitURL(child_id, GURL(origin.Serialize()));
635 // CanRequestURL should still allow all web-safe schemes. See 674 }
636 // https://crbug.com/515309.
637 if (IsWebSafeScheme(url.scheme()))
638 return true; // The scheme has been white-listed for every child process.
639 675
640 { 676 {
641 base::AutoLock lock(lock_); 677 base::AutoLock lock(lock_);
642 678
679 // Most schemes can commit in any process. Note that we check
680 // schemes_okay_to_commit_in_any_process_ here, which is stricter than
681 // IsWebSafeScheme().
682 //
683 // TODO(creis, nick): https://crbug.com/515309: in generalized Site
684 // Isolation and/or --site-per-process, there will be no such thing as a
685 // scheme that is okay to commit in any process. Instead, an URL from a site
686 // that is isolated may only be committed in a process dedicated to that
687 // site, so CanCommitURL will need to rely on explicit, per-process grants.
688 // Note how today, even with extension isolation, the line below does not
689 // enforce that http pages cannot commit in an extension process.
Charlie Reis 2016/09/29 21:39:37 Good point.
ncarter (slow) 2016/09/29 22:04:02 Done.
690 if (base::ContainsKey(schemes_okay_to_commit_in_any_process_, url.scheme()))
691 return true;
692
643 SecurityStateMap::iterator state = security_state_.find(child_id); 693 SecurityStateMap::iterator state = security_state_.find(child_id);
644 if (state == security_state_.end()) 694 if (state == security_state_.end())
645 return false; 695 return false;
646 696
647 // Otherwise, we consult the child process's security state to see if it is 697 // Otherwise, we consult the child process's security state to see if it is
648 // allowed to commit the URL. 698 // allowed to commit the URL.
649 return state->second->CanCommitURL(url); 699 return state->second->CanCommitURL(url);
650 } 700 }
651 } 701 }
652 702
653 bool ChildProcessSecurityPolicyImpl::CanSetAsOriginHeader(int child_id, 703 bool ChildProcessSecurityPolicyImpl::CanSetAsOriginHeader(int child_id,
654 const GURL& url) { 704 const GURL& url) {
655 if (!url.is_valid()) 705 if (!url.is_valid())
656 return false; // Can't set invalid URLs as origin headers. 706 return false; // Can't set invalid URLs as origin headers.
657 707
658 // Suborigin URLs are a special case and are allowed to be an origin header. 708 // Suborigin URLs are a special case and are allowed to be an origin header.
659 if (url.scheme() == kHttpSuboriginScheme || 709 if (url.scheme() == kHttpSuboriginScheme ||
660 url.scheme() == kHttpsSuboriginScheme) { 710 url.scheme() == kHttpsSuboriginScheme) {
661 DCHECK(IsPseudoScheme(url.scheme())); 711 DCHECK(IsPseudoScheme(url.scheme()));
662 return true; 712 return true;
663 } 713 }
664 714
665 return CanCommitURL(child_id, url); 715 // If this process can commit |url|, it can use |url| as an origin for
716 // outbound requests.
717 if (CanCommitURL(child_id, url))
718 return true;
719
720 // Allow schemes which may come from scripts executing in isolated worlds;
721 // XHRs issued by such scripts reflect the script origin rather than the
722 // document origin.
723 {
724 base::AutoLock lock(lock_);
725 if (base::ContainsKey(schemes_okay_to_appear_as_origin_headers_,
Charlie Reis 2016/09/29 21:39:37 Now I see why Joel's CanSetAsOriginHeader refactor
ncarter (slow) 2016/09/29 22:04:02 Yeah, well-timed ... except that it'll complicate
726 url.scheme()))
727 return true;
728 }
729 return false;
666 } 730 }
667 731
668 bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id, 732 bool ChildProcessSecurityPolicyImpl::CanReadFile(int child_id,
669 const base::FilePath& file) { 733 const base::FilePath& file) {
670 return HasPermissionsForFile(child_id, file, READ_FILE_GRANT); 734 return HasPermissionsForFile(child_id, file, READ_FILE_GRANT);
671 } 735 }
672 736
673 bool ChildProcessSecurityPolicyImpl::CanReadAllFiles( 737 bool ChildProcessSecurityPolicyImpl::CanReadAllFiles(
674 int child_id, 738 int child_id,
675 const std::vector<base::FilePath>& files) { 739 const std::vector<base::FilePath>& files) {
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
899 base::AutoLock lock(lock_); 963 base::AutoLock lock(lock_);
900 964
901 SecurityStateMap::iterator state = security_state_.find(child_id); 965 SecurityStateMap::iterator state = security_state_.find(child_id);
902 if (state == security_state_.end()) 966 if (state == security_state_.end())
903 return false; 967 return false;
904 968
905 return state->second->can_send_midi_sysex(); 969 return state->second->can_send_midi_sysex();
906 } 970 }
907 971
908 } // namespace content 972 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698