/src/mozilla-central/dom/ipc/nsIContentParent.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsIContentParent.h" |
8 | | |
9 | | #include "mozilla/Preferences.h" |
10 | | #include "mozilla/dom/File.h" |
11 | | #include "mozilla/dom/ContentParent.h" |
12 | | #include "mozilla/dom/ContentBridgeParent.h" |
13 | | #include "mozilla/dom/ContentProcessManager.h" |
14 | | #include "mozilla/dom/PTabContext.h" |
15 | | #include "mozilla/dom/PermissionMessageUtils.h" |
16 | | #include "mozilla/dom/ProcessMessageManager.h" |
17 | | #include "mozilla/dom/TabParent.h" |
18 | | #include "mozilla/dom/ipc/IPCBlobInputStreamParent.h" |
19 | | #include "mozilla/dom/ipc/StructuredCloneData.h" |
20 | | #include "mozilla/jsipc/CrossProcessObjectWrappers.h" |
21 | | #include "mozilla/ipc/FileDescriptorSetParent.h" |
22 | | #include "mozilla/ipc/PFileDescriptorSetParent.h" |
23 | | #include "mozilla/ipc/IPCStreamAlloc.h" |
24 | | #include "mozilla/ipc/IPCStreamDestination.h" |
25 | | #include "mozilla/ipc/IPCStreamSource.h" |
26 | | #include "mozilla/Unused.h" |
27 | | |
28 | | #include "nsIWebBrowserChrome.h" |
29 | | #include "nsPrintfCString.h" |
30 | | #include "xpcpublic.h" |
31 | | |
32 | | using namespace mozilla::jsipc; |
33 | | |
34 | | // XXX need another bug to move this to a common header. |
35 | | #ifdef DISABLE_ASSERTS_FOR_FUZZING |
36 | | #define ASSERT_UNLESS_FUZZING(...) do { } while (0) |
37 | | #else |
38 | 0 | #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__) |
39 | | #endif |
40 | | |
41 | | namespace mozilla { |
42 | | namespace dom { |
43 | | |
44 | | nsIContentParent::nsIContentParent() |
45 | 0 | { |
46 | 0 | mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true); |
47 | 0 | } |
48 | | |
49 | | ContentParent* |
50 | | nsIContentParent::AsContentParent() |
51 | 0 | { |
52 | 0 | MOZ_ASSERT(IsContentParent()); |
53 | 0 | return static_cast<ContentParent*>(this); |
54 | 0 | } |
55 | | |
56 | | ContentBridgeParent* |
57 | | nsIContentParent::AsContentBridgeParent() |
58 | 0 | { |
59 | 0 | MOZ_ASSERT(IsContentBridgeParent()); |
60 | 0 | return static_cast<ContentBridgeParent*>(this); |
61 | 0 | } |
62 | | |
63 | | PJavaScriptParent* |
64 | | nsIContentParent::AllocPJavaScriptParent() |
65 | 0 | { |
66 | 0 | return NewJavaScriptParent(); |
67 | 0 | } |
68 | | |
69 | | bool |
70 | | nsIContentParent::DeallocPJavaScriptParent(PJavaScriptParent* aParent) |
71 | 0 | { |
72 | 0 | ReleaseJavaScriptParent(aParent); |
73 | 0 | return true; |
74 | 0 | } |
75 | | |
76 | | bool |
77 | | nsIContentParent::CanOpenBrowser(const IPCTabContext& aContext) |
78 | 0 | { |
79 | 0 | // (PopupIPCTabContext lets the child process prove that it has access to |
80 | 0 | // the app it's trying to open.) |
81 | 0 | // On e10s we also allow UnsafeTabContext to allow service workers to open |
82 | 0 | // windows. This is enforced in MaybeInvalidTabContext. |
83 | 0 | if (aContext.type() != IPCTabContext::TPopupIPCTabContext && |
84 | 0 | aContext.type() != IPCTabContext::TUnsafeIPCTabContext) { |
85 | 0 | ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type. Aborting AllocPBrowserParent."); |
86 | 0 | return false; |
87 | 0 | } |
88 | 0 |
|
89 | 0 | if (aContext.type() == IPCTabContext::TPopupIPCTabContext) { |
90 | 0 | const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext(); |
91 | 0 | if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) { |
92 | 0 | ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type. Aborting AllocPBrowserParent."); |
93 | 0 | return false; |
94 | 0 | } |
95 | 0 |
|
96 | 0 | auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent()); |
97 | 0 | if (!opener) { |
98 | 0 | ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent."); |
99 | 0 | return false; |
100 | 0 | } |
101 | 0 |
|
102 | 0 | // Popup windows of isMozBrowserElement frames must be isMozBrowserElement if |
103 | 0 | // the parent isMozBrowserElement. Allocating a !isMozBrowserElement frame with |
104 | 0 | // same app ID would allow the content to access data it's not supposed to. |
105 | 0 | if (!popupContext.isMozBrowserElement() && opener->IsMozBrowserElement()) { |
106 | 0 | ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent."); |
107 | 0 | return false; |
108 | 0 | } |
109 | 0 | } |
110 | 0 |
|
111 | 0 | MaybeInvalidTabContext tc(aContext); |
112 | 0 | if (!tc.IsValid()) { |
113 | 0 | NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) " |
114 | 0 | "Aborting AllocPBrowserParent.", |
115 | 0 | tc.GetInvalidReason()).get()); |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 |
|
119 | 0 | return true; |
120 | 0 | } |
121 | | |
122 | | PBrowserParent* |
123 | | nsIContentParent::AllocPBrowserParent(const TabId& aTabId, |
124 | | const TabId& aSameTabGroupAs, |
125 | | const IPCTabContext& aContext, |
126 | | const uint32_t& aChromeFlags, |
127 | | const ContentParentId& aCpId, |
128 | | const bool& aIsForBrowser) |
129 | 0 | { |
130 | 0 | MOZ_ASSERT(!aSameTabGroupAs); |
131 | 0 |
|
132 | 0 | Unused << aCpId; |
133 | 0 | Unused << aIsForBrowser; |
134 | 0 |
|
135 | 0 | if (!CanOpenBrowser(aContext)) { |
136 | 0 | return nullptr; |
137 | 0 | } |
138 | 0 | |
139 | 0 | uint32_t chromeFlags = aChromeFlags; |
140 | 0 | TabId openerTabId(0); |
141 | 0 | ContentParentId openerCpId(0); |
142 | 0 | if (aContext.type() == IPCTabContext::TPopupIPCTabContext) { |
143 | 0 | // CanOpenBrowser has ensured that the IPCTabContext is of |
144 | 0 | // type PopupIPCTabContext, and that the opener TabParent is |
145 | 0 | // reachable. |
146 | 0 | const PopupIPCTabContext& popupContext = aContext.get_PopupIPCTabContext(); |
147 | 0 | auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent()); |
148 | 0 | openerTabId = opener->GetTabId(); |
149 | 0 | openerCpId = opener->Manager()->ChildID(); |
150 | 0 |
|
151 | 0 | // We must ensure that the private browsing and remoteness flags |
152 | 0 | // match those of the opener. |
153 | 0 | nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext(); |
154 | 0 | if (!loadContext) { |
155 | 0 | return nullptr; |
156 | 0 | } |
157 | 0 | |
158 | 0 | bool isPrivate; |
159 | 0 | loadContext->GetUsePrivateBrowsing(&isPrivate); |
160 | 0 | if (isPrivate) { |
161 | 0 | chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; |
162 | 0 | } |
163 | 0 | } |
164 | 0 |
|
165 | 0 | if (openerTabId > 0 || |
166 | 0 | aContext.type() == IPCTabContext::TUnsafeIPCTabContext) { |
167 | 0 | // Creation of PBrowser triggered from grandchild process is currently |
168 | 0 | // broken and not supported (i.e. this code path doesn't work in |
169 | 0 | // ContentBridgeParent). |
170 | 0 | // |
171 | 0 | // If you're working on fixing the code path for ContentBridgeParent, |
172 | 0 | // remember to handle the remote frame registration below carefully as it |
173 | 0 | // has to be registered in parent process. |
174 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
175 | 0 | if (!XRE_IsParentProcess()) { |
176 | 0 | return nullptr; |
177 | 0 | } |
178 | 0 | |
179 | 0 | // The creation of PBrowser was triggered from content process through |
180 | 0 | // either window.open() or service worker's openWindow(). |
181 | 0 | // We need to register remote frame with the child generated tab id. |
182 | 0 | ContentProcessManager* cpm = ContentProcessManager::GetSingleton(); |
183 | 0 | if (!cpm->RegisterRemoteFrame(aTabId, openerCpId, openerTabId, aContext, aCpId)) { |
184 | 0 | return nullptr; |
185 | 0 | } |
186 | 0 | } |
187 | 0 | |
188 | 0 | // And because we're allocating a remote browser, of course the |
189 | 0 | // window is remote. |
190 | 0 | chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW; |
191 | 0 |
|
192 | 0 | MaybeInvalidTabContext tc(aContext); |
193 | 0 | MOZ_ASSERT(tc.IsValid()); |
194 | 0 | TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), chromeFlags); |
195 | 0 |
|
196 | 0 | // We release this ref in DeallocPBrowserParent() |
197 | 0 | NS_ADDREF(parent); |
198 | 0 | return parent; |
199 | 0 | } |
200 | | |
201 | | bool |
202 | | nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame) |
203 | 0 | { |
204 | 0 | TabParent* parent = TabParent::GetFrom(aFrame); |
205 | 0 | NS_RELEASE(parent); |
206 | 0 | return true; |
207 | 0 | } |
208 | | |
209 | | mozilla::ipc::IPCResult |
210 | | nsIContentParent::RecvPBrowserConstructor(PBrowserParent* actor, |
211 | | const TabId& tabId, |
212 | | const TabId& sameTabGroupAs, |
213 | | const IPCTabContext& context, |
214 | | const uint32_t& chromeFlags, |
215 | | const ContentParentId& cpId, |
216 | | const bool& isForBrowser) |
217 | 0 | { |
218 | 0 | TabParent* parent = TabParent::GetFrom(actor); |
219 | 0 | // When enabling input event prioritization, input events may preempt other |
220 | 0 | // normal priority IPC messages. To prevent the input events preempt |
221 | 0 | // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to |
222 | 0 | // notify parent that TabChild is created. In this case, PBrowser is initiated |
223 | 0 | // from content so that we can set TabParent as ready to handle input events. |
224 | 0 | parent->SetReadyToHandleInputEvents(); |
225 | 0 | return IPC_OK(); |
226 | 0 | } |
227 | | |
228 | | PIPCBlobInputStreamParent* |
229 | | nsIContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID, |
230 | | const uint64_t& aSize) |
231 | 0 | { |
232 | 0 | MOZ_CRASH("PIPCBlobInputStreamParent actors should be manually constructed!"); |
233 | 0 | return nullptr; |
234 | 0 | } |
235 | | |
236 | | bool |
237 | | nsIContentParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor) |
238 | 0 | { |
239 | 0 | RefPtr<IPCBlobInputStreamParent> actor = |
240 | 0 | dont_AddRef(static_cast<IPCBlobInputStreamParent*>(aActor)); |
241 | 0 | return true; |
242 | 0 | } |
243 | | |
244 | | mozilla::ipc::IPCResult |
245 | | nsIContentParent::RecvSyncMessage(const nsString& aMsg, |
246 | | const ClonedMessageData& aData, |
247 | | InfallibleTArray<CpowEntry>&& aCpows, |
248 | | const IPC::Principal& aPrincipal, |
249 | | nsTArray<ipc::StructuredCloneData>* aRetvals) |
250 | 0 | { |
251 | 0 | AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING( |
252 | 0 | "nsIContentParent::RecvSyncMessage", OTHER, aMsg); |
253 | 0 |
|
254 | 0 | CrossProcessCpowHolder cpows(this, aCpows); |
255 | 0 | RefPtr<nsFrameMessageManager> ppm = mMessageManager; |
256 | 0 | if (ppm) { |
257 | 0 | ipc::StructuredCloneData data; |
258 | 0 | ipc::UnpackClonedMessageDataForParent(aData, data); |
259 | 0 |
|
260 | 0 | ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, &cpows, aPrincipal, aRetvals, |
261 | 0 | IgnoreErrors()); |
262 | 0 | } |
263 | 0 | return IPC_OK(); |
264 | 0 | } |
265 | | |
266 | | mozilla::ipc::IPCResult |
267 | | nsIContentParent::RecvRpcMessage(const nsString& aMsg, |
268 | | const ClonedMessageData& aData, |
269 | | InfallibleTArray<CpowEntry>&& aCpows, |
270 | | const IPC::Principal& aPrincipal, |
271 | | nsTArray<ipc::StructuredCloneData>* aRetvals) |
272 | 0 | { |
273 | 0 | AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING( |
274 | 0 | "nsIContentParent::RecvRpcMessage", OTHER, aMsg); |
275 | 0 |
|
276 | 0 | CrossProcessCpowHolder cpows(this, aCpows); |
277 | 0 | RefPtr<nsFrameMessageManager> ppm = mMessageManager; |
278 | 0 | if (ppm) { |
279 | 0 | ipc::StructuredCloneData data; |
280 | 0 | ipc::UnpackClonedMessageDataForParent(aData, data); |
281 | 0 |
|
282 | 0 | ppm->ReceiveMessage(ppm, nullptr, aMsg, true, &data, &cpows, aPrincipal, aRetvals, |
283 | 0 | IgnoreErrors()); |
284 | 0 | } |
285 | 0 | return IPC_OK(); |
286 | 0 | } |
287 | | |
288 | | PFileDescriptorSetParent* |
289 | | nsIContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD) |
290 | 0 | { |
291 | 0 | return new FileDescriptorSetParent(aFD); |
292 | 0 | } |
293 | | |
294 | | bool |
295 | | nsIContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor) |
296 | 0 | { |
297 | 0 | delete static_cast<FileDescriptorSetParent*>(aActor); |
298 | 0 | return true; |
299 | 0 | } |
300 | | |
301 | | PChildToParentStreamParent* |
302 | | nsIContentParent::AllocPChildToParentStreamParent() |
303 | 0 | { |
304 | 0 | return mozilla::ipc::AllocPChildToParentStreamParent(); |
305 | 0 | } |
306 | | |
307 | | bool |
308 | | nsIContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) |
309 | 0 | { |
310 | 0 | delete aActor; |
311 | 0 | return true; |
312 | 0 | } |
313 | | |
314 | | PParentToChildStreamParent* |
315 | | nsIContentParent::AllocPParentToChildStreamParent() |
316 | 0 | { |
317 | 0 | MOZ_CRASH("PParentToChildStreamChild actors should be manually constructed!"); |
318 | 0 | } |
319 | | |
320 | | bool |
321 | | nsIContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) |
322 | 0 | { |
323 | 0 | delete aActor; |
324 | 0 | return true; |
325 | 0 | } |
326 | | |
327 | | mozilla::ipc::IPCResult |
328 | | nsIContentParent::RecvAsyncMessage(const nsString& aMsg, |
329 | | InfallibleTArray<CpowEntry>&& aCpows, |
330 | | const IPC::Principal& aPrincipal, |
331 | | const ClonedMessageData& aData) |
332 | 0 | { |
333 | 0 | AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING( |
334 | 0 | "nsIContentParent::RecvAsyncMessage", OTHER, aMsg); |
335 | 0 |
|
336 | 0 | CrossProcessCpowHolder cpows(this, aCpows); |
337 | 0 | RefPtr<nsFrameMessageManager> ppm = mMessageManager; |
338 | 0 | if (ppm) { |
339 | 0 | ipc::StructuredCloneData data; |
340 | 0 | ipc::UnpackClonedMessageDataForParent(aData, data); |
341 | 0 |
|
342 | 0 | ppm->ReceiveMessage(ppm, nullptr, aMsg, false, &data, &cpows, aPrincipal, nullptr, |
343 | 0 | IgnoreErrors()); |
344 | 0 | } |
345 | 0 | return IPC_OK(); |
346 | 0 | } |
347 | | |
348 | | } // namespace dom |
349 | | } // namespace mozilla |