|
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/. */ |
|
7 |
|
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" |
|
22 |
|
23 #include <algorithm> |
|
24 |
|
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 } |
|
34 |
|
35 class nsIPrincipal; |
|
36 #endif |
|
37 |
|
38 namespace mozilla { |
|
39 |
|
40 #ifdef MOZ_CHILD_PERMISSIONS |
|
41 |
|
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 } |
|
51 |
|
52 TabParent* tab = static_cast<TabParent*>(aActor); |
|
53 nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp(); |
|
54 bool aValid = false; |
|
55 |
|
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 } |
|
81 |
|
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 } |
|
90 |
|
91 TabParent* tab = static_cast<TabParent*>(aActor); |
|
92 nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp(); |
|
93 |
|
94 bool valid = false; |
|
95 |
|
96 if (app) { |
|
97 unsigned short appStatus = 0; |
|
98 if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) { |
|
99 valid = appStatus == aStatus; |
|
100 } |
|
101 } |
|
102 |
|
103 return valid; |
|
104 } |
|
105 |
|
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 } |
|
118 |
|
119 NS_ERROR( |
|
120 nsPrintfCString( |
|
121 "Security problem: Content process does not have `%s'. It will be killed.\n", |
|
122 aCapability).get()); |
|
123 |
|
124 static_cast<ContentParent*>(aActor)->KillHard(); |
|
125 |
|
126 return false; |
|
127 } |
|
128 |
|
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 } |
|
140 |
|
141 NS_ERROR( |
|
142 nsPrintfCString( |
|
143 "Security problem: Content process does not have `%d' status. It will be killed.", |
|
144 aStatus).get()); |
|
145 |
|
146 static_cast<ContentParent*>(aActor)->KillHard(); |
|
147 |
|
148 return false; |
|
149 } |
|
150 |
|
151 bool |
|
152 AssertAppProcess(PHalParent* aActor, |
|
153 AssertAppProcessType aType, |
|
154 const char* aCapability) |
|
155 { |
|
156 return AssertAppProcess(aActor->Manager(), aType, aCapability); |
|
157 } |
|
158 |
|
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 } |
|
168 |
|
169 uint32_t principalAppId = aPrincipal->GetAppId(); |
|
170 bool inBrowserElement = aPrincipal->GetIsInBrowserElement(); |
|
171 |
|
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 } |
|
186 |
|
187 NS_WARNING("Principal is invalid, killing app process"); |
|
188 static_cast<ContentParent*>(aActor)->KillHard(); |
|
189 return false; |
|
190 } |
|
191 |
|
192 already_AddRefed<nsIPrincipal> |
|
193 GetAppPrincipal(uint32_t aAppId) |
|
194 { |
|
195 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); |
|
196 |
|
197 nsCOMPtr<mozIApplication> app; |
|
198 nsresult rv = appsService->GetAppByLocalId(aAppId, getter_AddRefs(app)); |
|
199 NS_ENSURE_SUCCESS(rv, nullptr); |
|
200 |
|
201 nsString origin; |
|
202 rv = app->GetOrigin(origin); |
|
203 NS_ENSURE_SUCCESS(rv, nullptr); |
|
204 |
|
205 nsCOMPtr<nsIURI> uri; |
|
206 NS_NewURI(getter_AddRefs(uri), origin); |
|
207 |
|
208 nsCOMPtr<nsIScriptSecurityManager> secMan = |
|
209 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); |
|
210 |
|
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 } |
|
217 |
|
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 } |
|
226 |
|
227 nsCOMPtr<nsIPermissionManager> pm = |
|
228 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); |
|
229 NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION); |
|
230 |
|
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 } |
|
241 |
|
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 } |
|
249 |
|
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 } |
|
256 |
|
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 } |
|
263 |
|
264 if (appPerm == nsIPermissionManager::ALLOW_ACTION || |
|
265 permission == nsIPermissionManager::ALLOW_ACTION) { |
|
266 return nsIPermissionManager::ALLOW_ACTION; |
|
267 } |
|
268 |
|
269 NS_RUNTIMEABORT("Invalid permission value"); |
|
270 return nsIPermissionManager::DENY_ACTION; |
|
271 } |
|
272 |
|
273 #else |
|
274 |
|
275 bool |
|
276 AssertAppProcess(mozilla::dom::PBrowserParent* aActor, |
|
277 AssertAppProcessType aType, |
|
278 const char* aCapability) |
|
279 { |
|
280 return true; |
|
281 } |
|
282 |
|
283 bool |
|
284 AssertAppStatus(mozilla::dom::PBrowserParent* aActor, |
|
285 unsigned short aStatus) |
|
286 { |
|
287 return true; |
|
288 } |
|
289 |
|
290 |
|
291 bool |
|
292 AssertAppProcess(mozilla::dom::PContentParent* aActor, |
|
293 AssertAppProcessType aType, |
|
294 const char* aCapability) |
|
295 { |
|
296 return true; |
|
297 } |
|
298 |
|
299 bool |
|
300 AssertAppStatus(mozilla::dom::PContentParent* aActor, |
|
301 unsigned short aStatus) |
|
302 { |
|
303 return true; |
|
304 } |
|
305 |
|
306 bool |
|
307 AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor, |
|
308 AssertAppProcessType aType, |
|
309 const char* aCapability) |
|
310 { |
|
311 return true; |
|
312 } |
|
313 |
|
314 bool |
|
315 AssertAppPrincipal(mozilla::dom::PContentParent* aActor, |
|
316 nsIPrincipal* aPrincipal) |
|
317 { |
|
318 return true; |
|
319 } |
|
320 |
|
321 uint32_t |
|
322 CheckPermission(mozilla::dom::PContentParent* aActor, |
|
323 nsIPrincipal* aPrincipal, |
|
324 const char* aPermission) |
|
325 { |
|
326 return nsIPermissionManager::ALLOW_ACTION; |
|
327 } |
|
328 |
|
329 #endif |
|
330 |
|
331 } // namespace mozilla |