Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "AppProcessChecker.h"
9 #include "nsIPermissionManager.h"
10 #ifdef MOZ_CHILD_PERMISSIONS
11 #include "ContentParent.h"
12 #include "mozIApplication.h"
13 #include "mozilla/hal_sandbox/PHalParent.h"
14 #include "nsIAppsService.h"
15 #include "nsIPrincipal.h"
16 #include "nsIScriptSecurityManager.h"
17 #include "nsPrintfCString.h"
18 #include "nsIURI.h"
19 #include "nsNetUtil.h"
20 #include "nsServiceManagerUtils.h"
21 #include "TabParent.h"
23 #include <algorithm>
25 using namespace mozilla::dom;
26 using namespace mozilla::hal_sandbox;
27 using namespace mozilla::services;
28 #else
29 namespace mozilla {
30 namespace dom {
31 class PContentParent;
32 }
33 }
35 class nsIPrincipal;
36 #endif
38 namespace mozilla {
40 #ifdef MOZ_CHILD_PERMISSIONS
42 bool
43 AssertAppProcess(PBrowserParent* aActor,
44 AssertAppProcessType aType,
45 const char* aCapability)
46 {
47 if (!aActor) {
48 NS_WARNING("Testing process capability for null actor");
49 return false;
50 }
52 TabParent* tab = static_cast<TabParent*>(aActor);
53 nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
54 bool aValid = false;
56 // isBrowser frames inherit their app descriptor to identify their
57 // data storage, but they don't inherit the capability associated
58 // with that descriptor.
59 if (app && (aType == ASSERT_APP_HAS_PERMISSION || !tab->IsBrowserElement())) {
60 switch (aType) {
61 case ASSERT_APP_HAS_PERMISSION:
62 case ASSERT_APP_PROCESS_PERMISSION:
63 if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) {
64 aValid = false;
65 }
66 break;
67 case ASSERT_APP_PROCESS_MANIFEST_URL: {
68 nsAutoString manifestURL;
69 if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) &&
70 manifestURL.EqualsASCII(aCapability)) {
71 aValid = true;
72 }
73 break;
74 }
75 default:
76 break;
77 }
78 }
79 return aValid;
80 }
82 bool
83 AssertAppStatus(PBrowserParent* aActor,
84 unsigned short aStatus)
85 {
86 if (!aActor) {
87 NS_WARNING("Testing process capability for null actor");
88 return false;
89 }
91 TabParent* tab = static_cast<TabParent*>(aActor);
92 nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
94 bool valid = false;
96 if (app) {
97 unsigned short appStatus = 0;
98 if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) {
99 valid = appStatus == aStatus;
100 }
101 }
103 return valid;
104 }
106 bool
107 AssertAppProcess(PContentParent* aActor,
108 AssertAppProcessType aType,
109 const char* aCapability)
110 {
111 const InfallibleTArray<PBrowserParent*>& browsers =
112 aActor->ManagedPBrowserParent();
113 for (uint32_t i = 0; i < browsers.Length(); ++i) {
114 if (AssertAppProcess(browsers[i], aType, aCapability)) {
115 return true;
116 }
117 }
119 NS_ERROR(
120 nsPrintfCString(
121 "Security problem: Content process does not have `%s'. It will be killed.\n",
122 aCapability).get());
124 static_cast<ContentParent*>(aActor)->KillHard();
126 return false;
127 }
129 bool
130 AssertAppStatus(PContentParent* aActor,
131 unsigned short aStatus)
132 {
133 const InfallibleTArray<PBrowserParent*>& browsers =
134 aActor->ManagedPBrowserParent();
135 for (uint32_t i = 0; i < browsers.Length(); ++i) {
136 if (AssertAppStatus(browsers[i], aStatus)) {
137 return true;
138 }
139 }
141 NS_ERROR(
142 nsPrintfCString(
143 "Security problem: Content process does not have `%d' status. It will be killed.",
144 aStatus).get());
146 static_cast<ContentParent*>(aActor)->KillHard();
148 return false;
149 }
151 bool
152 AssertAppProcess(PHalParent* aActor,
153 AssertAppProcessType aType,
154 const char* aCapability)
155 {
156 return AssertAppProcess(aActor->Manager(), aType, aCapability);
157 }
159 bool
160 AssertAppPrincipal(PContentParent* aActor,
161 nsIPrincipal* aPrincipal)
162 {
163 if (!aPrincipal) {
164 NS_WARNING("Principal is invalid, killing app process");
165 static_cast<ContentParent*>(aActor)->KillHard();
166 return false;
167 }
169 uint32_t principalAppId = aPrincipal->GetAppId();
170 bool inBrowserElement = aPrincipal->GetIsInBrowserElement();
172 // Check if the permission's appId matches a child we manage.
173 const InfallibleTArray<PBrowserParent*>& browsers =
174 aActor->ManagedPBrowserParent();
175 for (uint32_t i = 0; i < browsers.Length(); ++i) {
176 TabParent* tab = static_cast<TabParent*>(browsers[i]);
177 if (tab->OwnOrContainingAppId() == principalAppId) {
178 // If the child only runs inBrowserElement content and the principal claims
179 // it's not in a browser element, it's lying.
180 if (!tab->IsBrowserElement() || inBrowserElement) {
181 return true;
182 }
183 break;
184 }
185 }
187 NS_WARNING("Principal is invalid, killing app process");
188 static_cast<ContentParent*>(aActor)->KillHard();
189 return false;
190 }
192 already_AddRefed<nsIPrincipal>
193 GetAppPrincipal(uint32_t aAppId)
194 {
195 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
197 nsCOMPtr<mozIApplication> app;
198 nsresult rv = appsService->GetAppByLocalId(aAppId, getter_AddRefs(app));
199 NS_ENSURE_SUCCESS(rv, nullptr);
201 nsString origin;
202 rv = app->GetOrigin(origin);
203 NS_ENSURE_SUCCESS(rv, nullptr);
205 nsCOMPtr<nsIURI> uri;
206 NS_NewURI(getter_AddRefs(uri), origin);
208 nsCOMPtr<nsIScriptSecurityManager> secMan =
209 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
211 nsCOMPtr<nsIPrincipal> appPrincipal;
212 rv = secMan->GetAppCodebasePrincipal(uri, aAppId, false,
213 getter_AddRefs(appPrincipal));
214 NS_ENSURE_SUCCESS(rv, nullptr);
215 return appPrincipal.forget();
216 }
218 uint32_t
219 CheckPermission(PContentParent* aActor,
220 nsIPrincipal* aPrincipal,
221 const char* aPermission)
222 {
223 if (!AssertAppPrincipal(aActor, aPrincipal)) {
224 return nsIPermissionManager::DENY_ACTION;
225 }
227 nsCOMPtr<nsIPermissionManager> pm =
228 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
229 NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION);
231 // Make sure that `aPermission' is an app permission before checking the origin.
232 nsCOMPtr<nsIPrincipal> appPrincipal = GetAppPrincipal(aPrincipal->GetAppId());
233 uint32_t appPerm = nsIPermissionManager::UNKNOWN_ACTION;
234 nsresult rv = pm->TestExactPermissionFromPrincipal(appPrincipal, aPermission, &appPerm);
235 NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION);
236 // Setting to "deny" in the settings UI should deny everywhere.
237 if (appPerm == nsIPermissionManager::UNKNOWN_ACTION ||
238 appPerm == nsIPermissionManager::DENY_ACTION) {
239 return appPerm;
240 }
242 uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
243 rv = pm->TestExactPermissionFromPrincipal(aPrincipal, aPermission, &permission);
244 NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION);
245 if (permission == nsIPermissionManager::UNKNOWN_ACTION ||
246 permission == nsIPermissionManager::DENY_ACTION) {
247 return permission;
248 }
250 // For browser content (and if the app hasn't explicitly denied this),
251 // consider the requesting origin, not the app.
252 if (appPerm == nsIPermissionManager::PROMPT_ACTION &&
253 aPrincipal->GetIsInBrowserElement()) {
254 return permission;
255 }
257 // Setting to "prompt" in the settings UI should prompt everywhere in
258 // non-browser content.
259 if (appPerm == nsIPermissionManager::PROMPT_ACTION ||
260 permission == nsIPermissionManager::PROMPT_ACTION) {
261 return nsIPermissionManager::PROMPT_ACTION;
262 }
264 if (appPerm == nsIPermissionManager::ALLOW_ACTION ||
265 permission == nsIPermissionManager::ALLOW_ACTION) {
266 return nsIPermissionManager::ALLOW_ACTION;
267 }
269 NS_RUNTIMEABORT("Invalid permission value");
270 return nsIPermissionManager::DENY_ACTION;
271 }
273 #else
275 bool
276 AssertAppProcess(mozilla::dom::PBrowserParent* aActor,
277 AssertAppProcessType aType,
278 const char* aCapability)
279 {
280 return true;
281 }
283 bool
284 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
285 unsigned short aStatus)
286 {
287 return true;
288 }
291 bool
292 AssertAppProcess(mozilla::dom::PContentParent* aActor,
293 AssertAppProcessType aType,
294 const char* aCapability)
295 {
296 return true;
297 }
299 bool
300 AssertAppStatus(mozilla::dom::PContentParent* aActor,
301 unsigned short aStatus)
302 {
303 return true;
304 }
306 bool
307 AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor,
308 AssertAppProcessType aType,
309 const char* aCapability)
310 {
311 return true;
312 }
314 bool
315 AssertAppPrincipal(mozilla::dom::PContentParent* aActor,
316 nsIPrincipal* aPrincipal)
317 {
318 return true;
319 }
321 uint32_t
322 CheckPermission(mozilla::dom::PContentParent* aActor,
323 nsIPrincipal* aPrincipal,
324 const char* aPermission)
325 {
326 return nsIPermissionManager::ALLOW_ACTION;
327 }
329 #endif
331 } // namespace mozilla