1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/ipc/AppProcessChecker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,331 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=8 et : 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.9 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "AppProcessChecker.h" 1.12 +#include "nsIPermissionManager.h" 1.13 +#ifdef MOZ_CHILD_PERMISSIONS 1.14 +#include "ContentParent.h" 1.15 +#include "mozIApplication.h" 1.16 +#include "mozilla/hal_sandbox/PHalParent.h" 1.17 +#include "nsIAppsService.h" 1.18 +#include "nsIPrincipal.h" 1.19 +#include "nsIScriptSecurityManager.h" 1.20 +#include "nsPrintfCString.h" 1.21 +#include "nsIURI.h" 1.22 +#include "nsNetUtil.h" 1.23 +#include "nsServiceManagerUtils.h" 1.24 +#include "TabParent.h" 1.25 + 1.26 +#include <algorithm> 1.27 + 1.28 +using namespace mozilla::dom; 1.29 +using namespace mozilla::hal_sandbox; 1.30 +using namespace mozilla::services; 1.31 +#else 1.32 +namespace mozilla { 1.33 +namespace dom { 1.34 +class PContentParent; 1.35 +} 1.36 +} 1.37 + 1.38 +class nsIPrincipal; 1.39 +#endif 1.40 + 1.41 +namespace mozilla { 1.42 + 1.43 +#ifdef MOZ_CHILD_PERMISSIONS 1.44 + 1.45 +bool 1.46 +AssertAppProcess(PBrowserParent* aActor, 1.47 + AssertAppProcessType aType, 1.48 + const char* aCapability) 1.49 +{ 1.50 + if (!aActor) { 1.51 + NS_WARNING("Testing process capability for null actor"); 1.52 + return false; 1.53 + } 1.54 + 1.55 + TabParent* tab = static_cast<TabParent*>(aActor); 1.56 + nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp(); 1.57 + bool aValid = false; 1.58 + 1.59 + // isBrowser frames inherit their app descriptor to identify their 1.60 + // data storage, but they don't inherit the capability associated 1.61 + // with that descriptor. 1.62 + if (app && (aType == ASSERT_APP_HAS_PERMISSION || !tab->IsBrowserElement())) { 1.63 + switch (aType) { 1.64 + case ASSERT_APP_HAS_PERMISSION: 1.65 + case ASSERT_APP_PROCESS_PERMISSION: 1.66 + if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) { 1.67 + aValid = false; 1.68 + } 1.69 + break; 1.70 + case ASSERT_APP_PROCESS_MANIFEST_URL: { 1.71 + nsAutoString manifestURL; 1.72 + if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) && 1.73 + manifestURL.EqualsASCII(aCapability)) { 1.74 + aValid = true; 1.75 + } 1.76 + break; 1.77 + } 1.78 + default: 1.79 + break; 1.80 + } 1.81 + } 1.82 + return aValid; 1.83 +} 1.84 + 1.85 +bool 1.86 +AssertAppStatus(PBrowserParent* aActor, 1.87 + unsigned short aStatus) 1.88 +{ 1.89 + if (!aActor) { 1.90 + NS_WARNING("Testing process capability for null actor"); 1.91 + return false; 1.92 + } 1.93 + 1.94 + TabParent* tab = static_cast<TabParent*>(aActor); 1.95 + nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp(); 1.96 + 1.97 + bool valid = false; 1.98 + 1.99 + if (app) { 1.100 + unsigned short appStatus = 0; 1.101 + if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) { 1.102 + valid = appStatus == aStatus; 1.103 + } 1.104 + } 1.105 + 1.106 + return valid; 1.107 +} 1.108 + 1.109 +bool 1.110 +AssertAppProcess(PContentParent* aActor, 1.111 + AssertAppProcessType aType, 1.112 + const char* aCapability) 1.113 +{ 1.114 + const InfallibleTArray<PBrowserParent*>& browsers = 1.115 + aActor->ManagedPBrowserParent(); 1.116 + for (uint32_t i = 0; i < browsers.Length(); ++i) { 1.117 + if (AssertAppProcess(browsers[i], aType, aCapability)) { 1.118 + return true; 1.119 + } 1.120 + } 1.121 + 1.122 + NS_ERROR( 1.123 + nsPrintfCString( 1.124 + "Security problem: Content process does not have `%s'. It will be killed.\n", 1.125 + aCapability).get()); 1.126 + 1.127 + static_cast<ContentParent*>(aActor)->KillHard(); 1.128 + 1.129 + return false; 1.130 +} 1.131 + 1.132 +bool 1.133 +AssertAppStatus(PContentParent* aActor, 1.134 + unsigned short aStatus) 1.135 +{ 1.136 + const InfallibleTArray<PBrowserParent*>& browsers = 1.137 + aActor->ManagedPBrowserParent(); 1.138 + for (uint32_t i = 0; i < browsers.Length(); ++i) { 1.139 + if (AssertAppStatus(browsers[i], aStatus)) { 1.140 + return true; 1.141 + } 1.142 + } 1.143 + 1.144 + NS_ERROR( 1.145 + nsPrintfCString( 1.146 + "Security problem: Content process does not have `%d' status. It will be killed.", 1.147 + aStatus).get()); 1.148 + 1.149 + static_cast<ContentParent*>(aActor)->KillHard(); 1.150 + 1.151 + return false; 1.152 +} 1.153 + 1.154 +bool 1.155 +AssertAppProcess(PHalParent* aActor, 1.156 + AssertAppProcessType aType, 1.157 + const char* aCapability) 1.158 +{ 1.159 + return AssertAppProcess(aActor->Manager(), aType, aCapability); 1.160 +} 1.161 + 1.162 +bool 1.163 +AssertAppPrincipal(PContentParent* aActor, 1.164 + nsIPrincipal* aPrincipal) 1.165 +{ 1.166 + if (!aPrincipal) { 1.167 + NS_WARNING("Principal is invalid, killing app process"); 1.168 + static_cast<ContentParent*>(aActor)->KillHard(); 1.169 + return false; 1.170 + } 1.171 + 1.172 + uint32_t principalAppId = aPrincipal->GetAppId(); 1.173 + bool inBrowserElement = aPrincipal->GetIsInBrowserElement(); 1.174 + 1.175 + // Check if the permission's appId matches a child we manage. 1.176 + const InfallibleTArray<PBrowserParent*>& browsers = 1.177 + aActor->ManagedPBrowserParent(); 1.178 + for (uint32_t i = 0; i < browsers.Length(); ++i) { 1.179 + TabParent* tab = static_cast<TabParent*>(browsers[i]); 1.180 + if (tab->OwnOrContainingAppId() == principalAppId) { 1.181 + // If the child only runs inBrowserElement content and the principal claims 1.182 + // it's not in a browser element, it's lying. 1.183 + if (!tab->IsBrowserElement() || inBrowserElement) { 1.184 + return true; 1.185 + } 1.186 + break; 1.187 + } 1.188 + } 1.189 + 1.190 + NS_WARNING("Principal is invalid, killing app process"); 1.191 + static_cast<ContentParent*>(aActor)->KillHard(); 1.192 + return false; 1.193 +} 1.194 + 1.195 +already_AddRefed<nsIPrincipal> 1.196 +GetAppPrincipal(uint32_t aAppId) 1.197 +{ 1.198 + nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); 1.199 + 1.200 + nsCOMPtr<mozIApplication> app; 1.201 + nsresult rv = appsService->GetAppByLocalId(aAppId, getter_AddRefs(app)); 1.202 + NS_ENSURE_SUCCESS(rv, nullptr); 1.203 + 1.204 + nsString origin; 1.205 + rv = app->GetOrigin(origin); 1.206 + NS_ENSURE_SUCCESS(rv, nullptr); 1.207 + 1.208 + nsCOMPtr<nsIURI> uri; 1.209 + NS_NewURI(getter_AddRefs(uri), origin); 1.210 + 1.211 + nsCOMPtr<nsIScriptSecurityManager> secMan = 1.212 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); 1.213 + 1.214 + nsCOMPtr<nsIPrincipal> appPrincipal; 1.215 + rv = secMan->GetAppCodebasePrincipal(uri, aAppId, false, 1.216 + getter_AddRefs(appPrincipal)); 1.217 + NS_ENSURE_SUCCESS(rv, nullptr); 1.218 + return appPrincipal.forget(); 1.219 +} 1.220 + 1.221 +uint32_t 1.222 +CheckPermission(PContentParent* aActor, 1.223 + nsIPrincipal* aPrincipal, 1.224 + const char* aPermission) 1.225 +{ 1.226 + if (!AssertAppPrincipal(aActor, aPrincipal)) { 1.227 + return nsIPermissionManager::DENY_ACTION; 1.228 + } 1.229 + 1.230 + nsCOMPtr<nsIPermissionManager> pm = 1.231 + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); 1.232 + NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION); 1.233 + 1.234 + // Make sure that `aPermission' is an app permission before checking the origin. 1.235 + nsCOMPtr<nsIPrincipal> appPrincipal = GetAppPrincipal(aPrincipal->GetAppId()); 1.236 + uint32_t appPerm = nsIPermissionManager::UNKNOWN_ACTION; 1.237 + nsresult rv = pm->TestExactPermissionFromPrincipal(appPrincipal, aPermission, &appPerm); 1.238 + NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION); 1.239 + // Setting to "deny" in the settings UI should deny everywhere. 1.240 + if (appPerm == nsIPermissionManager::UNKNOWN_ACTION || 1.241 + appPerm == nsIPermissionManager::DENY_ACTION) { 1.242 + return appPerm; 1.243 + } 1.244 + 1.245 + uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; 1.246 + rv = pm->TestExactPermissionFromPrincipal(aPrincipal, aPermission, &permission); 1.247 + NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION); 1.248 + if (permission == nsIPermissionManager::UNKNOWN_ACTION || 1.249 + permission == nsIPermissionManager::DENY_ACTION) { 1.250 + return permission; 1.251 + } 1.252 + 1.253 + // For browser content (and if the app hasn't explicitly denied this), 1.254 + // consider the requesting origin, not the app. 1.255 + if (appPerm == nsIPermissionManager::PROMPT_ACTION && 1.256 + aPrincipal->GetIsInBrowserElement()) { 1.257 + return permission; 1.258 + } 1.259 + 1.260 + // Setting to "prompt" in the settings UI should prompt everywhere in 1.261 + // non-browser content. 1.262 + if (appPerm == nsIPermissionManager::PROMPT_ACTION || 1.263 + permission == nsIPermissionManager::PROMPT_ACTION) { 1.264 + return nsIPermissionManager::PROMPT_ACTION; 1.265 + } 1.266 + 1.267 + if (appPerm == nsIPermissionManager::ALLOW_ACTION || 1.268 + permission == nsIPermissionManager::ALLOW_ACTION) { 1.269 + return nsIPermissionManager::ALLOW_ACTION; 1.270 + } 1.271 + 1.272 + NS_RUNTIMEABORT("Invalid permission value"); 1.273 + return nsIPermissionManager::DENY_ACTION; 1.274 +} 1.275 + 1.276 +#else 1.277 + 1.278 +bool 1.279 +AssertAppProcess(mozilla::dom::PBrowserParent* aActor, 1.280 + AssertAppProcessType aType, 1.281 + const char* aCapability) 1.282 +{ 1.283 + return true; 1.284 +} 1.285 + 1.286 +bool 1.287 +AssertAppStatus(mozilla::dom::PBrowserParent* aActor, 1.288 + unsigned short aStatus) 1.289 +{ 1.290 + return true; 1.291 +} 1.292 + 1.293 + 1.294 +bool 1.295 +AssertAppProcess(mozilla::dom::PContentParent* aActor, 1.296 + AssertAppProcessType aType, 1.297 + const char* aCapability) 1.298 +{ 1.299 + return true; 1.300 +} 1.301 + 1.302 +bool 1.303 +AssertAppStatus(mozilla::dom::PContentParent* aActor, 1.304 + unsigned short aStatus) 1.305 +{ 1.306 + return true; 1.307 +} 1.308 + 1.309 +bool 1.310 +AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor, 1.311 + AssertAppProcessType aType, 1.312 + const char* aCapability) 1.313 +{ 1.314 + return true; 1.315 +} 1.316 + 1.317 +bool 1.318 +AssertAppPrincipal(mozilla::dom::PContentParent* aActor, 1.319 + nsIPrincipal* aPrincipal) 1.320 +{ 1.321 + return true; 1.322 +} 1.323 + 1.324 +uint32_t 1.325 +CheckPermission(mozilla::dom::PContentParent* aActor, 1.326 + nsIPrincipal* aPrincipal, 1.327 + const char* aPermission) 1.328 +{ 1.329 + return nsIPermissionManager::ALLOW_ACTION; 1.330 +} 1.331 + 1.332 +#endif 1.333 + 1.334 +} // namespace mozilla