Index: content/browser/loader/resource_dispatcher_host_impl.cc |
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc |
index 981c71ba454f337c573f6c9b64805d7934a13ce5..7b9d1cc5e25bfc3aa4b17d0e4893540d70d36252 100644 |
--- a/content/browser/loader/resource_dispatcher_host_impl.cc |
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc |
@@ -295,7 +295,8 @@ bool ShouldServiceRequest(int process_type, |
const ResourceRequest& request_data, |
const net::HttpRequestHeaders& headers, |
ResourceMessageFilter* filter, |
- ResourceContext* resource_context) { |
+ ResourceContext* resource_context, |
+ ResourceDispatcherHostImpl* host) { |
ChildProcessSecurityPolicyImpl* policy = |
ChildProcessSecurityPolicyImpl::GetInstance(); |
@@ -313,8 +314,7 @@ bool ShouldServiceRequest(int process_type, |
if (has_origin) { |
GURL origin(origin_string); |
if (!policy->CanCommitURL(child_id, origin) || |
- GetContentClient()->browser()->IsIllegalOrigin(resource_context, |
- child_id, origin)) { |
+ host->IsIllegalOrigin(resource_context, origin, child_id)) { |
VLOG(1) << "Killed renderer for illegal origin: " << origin_string; |
bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); |
return false; |
@@ -493,6 +493,16 @@ void NotifyForEachFrameFromUI( |
} // namespace |
+ResourceDispatcherHostImpl::OriginAccessInfo::OriginAccessInfo() { |
+} |
+ |
+ResourceDispatcherHostImpl::OriginAccessInfo::~OriginAccessInfo() { |
+} |
+ |
+ResourceDispatcherHostImpl::OriginAccessInfo::OriginAccessInfo( |
+ const OriginAccessInfo& other) { |
+} |
+ |
// static |
ResourceDispatcherHost* ResourceDispatcherHost::Get() { |
return g_resource_dispatcher_host; |
@@ -751,6 +761,145 @@ void ResourceDispatcherHostImpl::ClearLoginDelegateForRequest( |
} |
} |
+void ResourceDispatcherHostImpl::AddSchemeForAccessCheck( |
+ const std::string& scheme) { |
+ origins_for_access_check_.insert(scheme); |
+} |
+ |
+void ResourceDispatcherHostImpl::RegisterOriginForAccessChecks( |
+ const ResourceContext* context, |
+ const std::string& origin, |
+ OriginAccessCheckMask access_check_mask) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ GURL url(origin); |
+ // The following conditions need to apply before we can add access |
+ // information for an origin. |
+ // 1. The URL has to be valid. |
+ // 2. It has to have a valid host. |
+ // 3. The scheme has to be registered in the list of schemes being access |
+ // checked. |
+ if (!url.is_valid() || !url.has_host() || |
+ origins_for_access_check_.find(url.scheme()) == |
+ origins_for_access_check_.end()) { |
+ NOTREACHED() << "Invalid URL or unregistered scheme."; |
+ return; |
+ } |
+ |
+ OriginAccessInfoMap* origin_access_info_map = |
+ GetOriginAccessMapForResourceContext(context); |
+ DCHECK(origin_access_info_map->find(url.host()) == |
+ origin_access_info_map->end()); |
+ |
+ OriginAccessInfo access_info; |
+ access_info.access_check_mask = access_check_mask; |
+ |
+ (*origin_access_info_map)[url.host()] = access_info; |
+} |
+ |
+void ResourceDispatcherHostImpl::UnregisterOriginForAccessChecks( |
+ const ResourceContext* context, |
+ const std::string& origin) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ GURL url(origin); |
+ // The scheme has to be registered in the list of schemes being access |
+ // checked. |
+ if (origins_for_access_check_.find(url.scheme()) == |
+ origins_for_access_check_.end()) { |
+ NOTREACHED() << "Unregistered scheme for access check"; |
+ return; |
+ } |
+ OriginAccessInfoMap* origin_access_info_map = |
+ GetOriginAccessMapForResourceContext(context); |
+ OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
+ url.host()); |
+ if (index != origin_access_info_map->end()) |
+ origin_access_info_map->erase(index); |
+} |
+ |
+void ResourceDispatcherHostImpl::AddProcessForOrigin( |
+ const ResourceContext* context, |
+ const std::string& origin, |
+ int process_id, |
+ bool owner_process) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ GURL url(origin); |
+ // The following conditions need to apply before we can add the process to |
+ // the list of allowed processes for an origin. |
+ // 1. The URL has to be valid. |
+ // 2. It has to have a valid host. |
+ // 3. The scheme has to be registered in the list of schemes being access |
+ // checked. |
+ if (!url.is_valid() || !url.has_host() || |
+ origins_for_access_check_.find(url.scheme()) == |
+ origins_for_access_check_.end()) { |
+ NOTREACHED() << "Invalid URL or unregistered scheme."; |
+ return; |
+ } |
+ |
+ OriginAccessInfoMap* origin_access_info_map = |
+ GetOriginAccessMapForResourceContext(context); |
+ DCHECK(origin_access_info_map); |
+ |
+ OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
+ url.host()); |
+ // No need to add access information for an unregistered host. |
+ if (index == origin_access_info_map->end()) |
+ return; |
+ |
+ OriginAccessInfo& access_info = index->second; |
+ if (owner_process) { |
+ access_info.owner_processes[process_id]++; |
+ } else { |
+ access_info.other_processes[process_id]++; |
+ } |
+} |
+ |
+void ResourceDispatcherHostImpl::RemoveProcessForOrigin( |
+ const ResourceContext* context, |
+ const std::string& origin, |
+ int process_id, |
+ bool owner_process) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ GURL url(origin); |
+ // The scheme has to be registered in the list of schemes being access |
+ // checked. |
+ if (origins_for_access_check_.find(url.scheme()) == |
+ origins_for_access_check_.end()) { |
+ DCHECK(false); |
+ return; |
+ } |
+ |
+ OriginAccessInfoMap* origin_access_info_map = |
+ GetOriginAccessMapForResourceContext(context); |
+ DCHECK(origin_access_info_map); |
+ |
+ OriginAccessInfoMap::iterator index = origin_access_info_map->find( |
+ url.host()); |
+ // No need to add access information for an unregistered host. |
+ if (index == origin_access_info_map->end()) |
+ return; |
+ |
+ OriginAccessInfo& access_info = index->second; |
+ |
+ std::map<int, int>::iterator process_index; |
+ std::map<int, int>* process_map = nullptr; |
+ if (owner_process) { |
+ process_map = &access_info.owner_processes; |
+ } else { |
+ process_map = &access_info.other_processes; |
+ } |
+ process_index = process_map->find(process_id); |
+ // The process has to be there in the list. |
+ DCHECK(process_index != process_map->end()); |
+ process_index->second--; |
+ if (process_index->second == 0) |
+ process_map->erase(process_index); |
+} |
+ |
void ResourceDispatcherHostImpl::Shutdown() { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
BrowserThread::PostTask(BrowserThread::IO, |
@@ -1361,7 +1510,7 @@ void ResourceDispatcherHostImpl::BeginRequest( |
if (is_shutdown_ || |
!ShouldServiceRequest(process_type, child_id, request_data, headers, |
- filter_, resource_context)) { |
+ filter_, resource_context, this)) { |
AbortRequestBeforeItStarts(filter_, sync_result, request_id); |
return; |
} |
@@ -2607,4 +2756,61 @@ CertStore* ResourceDispatcherHostImpl::GetCertStore() { |
: CertStore::GetInstance(); |
} |
+ResourceDispatcherHostImpl::OriginAccessInfoMap* |
+ResourceDispatcherHostImpl::GetOriginAccessMapForResourceContext( |
+ const ResourceContext* context) { |
+ ResourceContextOriginMap::iterator context_index = |
+ context_origin_access_info_map_.find(context); |
+ if (context_index != context_origin_access_info_map_.end()) |
+ return context_index->second.get(); |
+ |
+ context_origin_access_info_map_[context].reset(new OriginAccessInfoMap); |
+ return context_origin_access_info_map_[context].get(); |
+} |
+ |
+bool ResourceDispatcherHostImpl::IsIllegalOrigin(ResourceContext* context, |
+ const GURL& origin, |
+ int child_process_id) { |
+ if (origins_for_access_check_.find(origin.scheme()) == |
+ origins_for_access_check_.end()) { |
+ return false; |
+ } |
+ |
+ OriginAccessInfoMap* origin_access_info_map = |
+ GetOriginAccessMapForResourceContext( |
+ const_cast<const ResourceContext*>(context)); |
+ DCHECK(origin_access_info_map); |
+ |
+ // If the origin is not found then this URL cannot be committed. |
+ OriginAccessInfoMap::iterator index = |
+ origin_access_info_map->find(origin.host()); |
+ if (index == origin_access_info_map->end()) |
+ return false; |
+ |
+ OriginAccessInfo& access_info = index->second; |
+ // Owner processes are allowed access by default. |
+ if (access_info.owner_processes.find(child_process_id) != |
+ access_info.owner_processes.end()) { |
+ return false; |
+ } |
+ |
+ DCHECK(access_info.access_check_mask >= DENY_FOR_NON_OWNERS && |
+ access_info.access_check_mask <= ACCESS_CHECK_MASK_LAST); |
+ |
+ if (access_info.access_check_mask == DENY_FOR_NON_OWNERS) |
+ return true; |
+ |
+ // No need to check for other processes here. |
+ if (access_info.access_check_mask == ALLOW_EVERYTHING) |
+ return false; |
+ |
+ // Processes in the other_processes list are allowed. |
+ if (access_info.other_processes.find(child_process_id) != |
+ access_info.other_processes.end()) { |
+ return false; |
+ } |
+ // The origin being accessed is not allowed for the |child_process_id|. |
+ return true; |
+} |
+ |
} // namespace content |