Line data Source code
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/TabParent.h"
17 : #include "mozilla/dom/ipc/IPCBlobInputStreamParent.h"
18 : #include "mozilla/dom/ipc/StructuredCloneData.h"
19 : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
20 : #include "mozilla/ipc/FileDescriptorSetParent.h"
21 : #include "mozilla/ipc/PFileDescriptorSetParent.h"
22 : #include "mozilla/ipc/IPCStreamAlloc.h"
23 : #include "mozilla/ipc/IPCStreamDestination.h"
24 : #include "mozilla/ipc/IPCStreamSource.h"
25 : #include "mozilla/Unused.h"
26 :
27 : #include "nsFrameMessageManager.h"
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 : #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
39 : #endif
40 :
41 : namespace mozilla {
42 : namespace dom {
43 :
44 2 : nsIContentParent::nsIContentParent()
45 : {
46 2 : mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true);
47 2 : }
48 :
49 : ContentParent*
50 3 : nsIContentParent::AsContentParent()
51 : {
52 3 : MOZ_ASSERT(IsContentParent());
53 3 : return static_cast<ContentParent*>(this);
54 : }
55 :
56 : ContentBridgeParent*
57 0 : nsIContentParent::AsContentBridgeParent()
58 : {
59 0 : MOZ_ASSERT(IsContentBridgeParent());
60 0 : return static_cast<ContentBridgeParent*>(this);
61 : }
62 :
63 : PJavaScriptParent*
64 1 : nsIContentParent::AllocPJavaScriptParent()
65 : {
66 1 : return NewJavaScriptParent();
67 : }
68 :
69 : bool
70 0 : nsIContentParent::DeallocPJavaScriptParent(PJavaScriptParent* aParent)
71 : {
72 0 : ReleaseJavaScriptParent(aParent);
73 0 : return true;
74 : }
75 :
76 : bool
77 0 : nsIContentParent::CanOpenBrowser(const IPCTabContext& aContext)
78 : {
79 : // (PopupIPCTabContext lets the child process prove that it has access to
80 : // the app it's trying to open.)
81 : // On e10s we also allow UnsafeTabContext to allow service workers to open
82 : // 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 : return false;
87 : }
88 :
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 : return false;
94 : }
95 :
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 : return false;
100 : }
101 :
102 : // Popup windows of isMozBrowserElement frames must be isMozBrowserElement if
103 : // the parent isMozBrowserElement. Allocating a !isMozBrowserElement frame with
104 : // 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 : return false;
108 : }
109 : }
110 :
111 0 : MaybeInvalidTabContext tc(aContext);
112 0 : if (!tc.IsValid()) {
113 0 : NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) "
114 : "Aborting AllocPBrowserParent.",
115 : tc.GetInvalidReason()).get());
116 0 : return false;
117 : }
118 :
119 0 : return true;
120 : }
121 :
122 : PBrowserParent*
123 0 : 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 : {
130 0 : MOZ_ASSERT(!aSameTabGroupAs);
131 :
132 : Unused << aCpId;
133 : Unused << aIsForBrowser;
134 :
135 0 : if (!CanOpenBrowser(aContext)) {
136 0 : return nullptr;
137 : }
138 :
139 0 : uint32_t chromeFlags = aChromeFlags;
140 0 : TabId openerTabId(0);
141 0 : ContentParentId openerCpId(0);
142 0 : if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
143 : // CanOpenBrowser has ensured that the IPCTabContext is of
144 : // type PopupIPCTabContext, and that the opener TabParent is
145 : // 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 :
151 : // We must ensure that the private browsing and remoteness flags
152 : // match those of the opener.
153 0 : nsCOMPtr<nsILoadContext> loadContext = opener->GetLoadContext();
154 0 : if (!loadContext) {
155 0 : return nullptr;
156 : }
157 :
158 : bool isPrivate;
159 0 : loadContext->GetUsePrivateBrowsing(&isPrivate);
160 0 : if (isPrivate) {
161 0 : chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
162 : }
163 : }
164 :
165 0 : if (openerTabId > 0 ||
166 0 : aContext.type() == IPCTabContext::TUnsafeIPCTabContext) {
167 : // Creation of PBrowser triggered from grandchild process is currently
168 : // broken and not supported (i.e. this code path doesn't work in
169 : // ContentBridgeParent).
170 : //
171 : // If you're working on fixing the code path for ContentBridgeParent,
172 : // remember to handle the remote frame registration below carefully as it
173 : // has to be registered in parent process.
174 0 : MOZ_ASSERT(XRE_IsParentProcess());
175 0 : if (!XRE_IsParentProcess()) {
176 0 : return nullptr;
177 : }
178 :
179 : // The creation of PBrowser was triggered from content process through
180 : // either window.open() or service worker's openWindow().
181 : // 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 : }
186 : }
187 :
188 : // And because we're allocating a remote browser, of course the
189 : // window is remote.
190 0 : chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
191 :
192 0 : MaybeInvalidTabContext tc(aContext);
193 0 : MOZ_ASSERT(tc.IsValid());
194 0 : TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), chromeFlags);
195 :
196 : // We release this ref in DeallocPBrowserParent()
197 0 : NS_ADDREF(parent);
198 0 : return parent;
199 : }
200 :
201 : bool
202 0 : nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
203 : {
204 0 : TabParent* parent = TabParent::GetFrom(aFrame);
205 0 : NS_RELEASE(parent);
206 0 : return true;
207 : }
208 :
209 : PIPCBlobInputStreamParent*
210 0 : nsIContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
211 : const uint64_t& aSize)
212 : {
213 0 : MOZ_CRASH("PIPCBlobInputStreamParent actors should be manually constructed!");
214 : return nullptr;
215 : }
216 :
217 : bool
218 0 : nsIContentParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor)
219 : {
220 0 : delete aActor;
221 0 : return true;
222 : }
223 :
224 : mozilla::ipc::IPCResult
225 0 : nsIContentParent::RecvSyncMessage(const nsString& aMsg,
226 : const ClonedMessageData& aData,
227 : InfallibleTArray<CpowEntry>&& aCpows,
228 : const IPC::Principal& aPrincipal,
229 : nsTArray<ipc::StructuredCloneData>* aRetvals)
230 : {
231 0 : NS_LossyConvertUTF16toASCII messageNameCStr(aMsg);
232 0 : AUTO_PROFILER_LABEL_DYNAMIC("nsIContentParent::RecvSyncMessage", EVENTS,
233 : messageNameCStr.get());
234 :
235 0 : CrossProcessCpowHolder cpows(this, aCpows);
236 0 : RefPtr<nsFrameMessageManager> ppm = mMessageManager;
237 0 : if (ppm) {
238 0 : ipc::StructuredCloneData data;
239 0 : ipc::UnpackClonedMessageDataForParent(aData, data);
240 :
241 0 : ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
242 0 : aMsg, true, &data, &cpows, aPrincipal, aRetvals);
243 : }
244 0 : return IPC_OK();
245 : }
246 :
247 : mozilla::ipc::IPCResult
248 0 : nsIContentParent::RecvRpcMessage(const nsString& aMsg,
249 : const ClonedMessageData& aData,
250 : InfallibleTArray<CpowEntry>&& aCpows,
251 : const IPC::Principal& aPrincipal,
252 : nsTArray<ipc::StructuredCloneData>* aRetvals)
253 : {
254 0 : NS_LossyConvertUTF16toASCII messageNameCStr(aMsg);
255 0 : AUTO_PROFILER_LABEL_DYNAMIC("nsIContentParent::RecvRpcMessage", EVENTS,
256 : messageNameCStr.get());
257 :
258 0 : CrossProcessCpowHolder cpows(this, aCpows);
259 0 : RefPtr<nsFrameMessageManager> ppm = mMessageManager;
260 0 : if (ppm) {
261 0 : ipc::StructuredCloneData data;
262 0 : ipc::UnpackClonedMessageDataForParent(aData, data);
263 :
264 0 : ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
265 0 : aMsg, true, &data, &cpows, aPrincipal, aRetvals);
266 : }
267 0 : return IPC_OK();
268 : }
269 :
270 : PFileDescriptorSetParent*
271 0 : nsIContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
272 : {
273 0 : return new FileDescriptorSetParent(aFD);
274 : }
275 :
276 : bool
277 0 : nsIContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
278 : {
279 0 : delete static_cast<FileDescriptorSetParent*>(aActor);
280 0 : return true;
281 : }
282 :
283 : PChildToParentStreamParent*
284 0 : nsIContentParent::AllocPChildToParentStreamParent()
285 : {
286 0 : return mozilla::ipc::AllocPChildToParentStreamParent();
287 : }
288 :
289 : bool
290 0 : nsIContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
291 : {
292 0 : delete aActor;
293 0 : return true;
294 : }
295 :
296 : PParentToChildStreamParent*
297 0 : nsIContentParent::AllocPParentToChildStreamParent()
298 : {
299 0 : MOZ_CRASH("PParentToChildStreamChild actors should be manually constructed!");
300 : }
301 :
302 : bool
303 0 : nsIContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
304 : {
305 0 : delete aActor;
306 0 : return true;
307 : }
308 :
309 : mozilla::ipc::IPCResult
310 3 : nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
311 : InfallibleTArray<CpowEntry>&& aCpows,
312 : const IPC::Principal& aPrincipal,
313 : const ClonedMessageData& aData)
314 : {
315 6 : NS_LossyConvertUTF16toASCII messageNameCStr(aMsg);
316 6 : AUTO_PROFILER_LABEL_DYNAMIC("nsIContentParent::RecvAsyncMessage", EVENTS,
317 : messageNameCStr.get());
318 :
319 6 : CrossProcessCpowHolder cpows(this, aCpows);
320 6 : RefPtr<nsFrameMessageManager> ppm = mMessageManager;
321 3 : if (ppm) {
322 6 : ipc::StructuredCloneData data;
323 3 : ipc::UnpackClonedMessageDataForParent(aData, data);
324 :
325 3 : ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr,
326 3 : aMsg, false, &data, &cpows, aPrincipal, nullptr);
327 : }
328 6 : return IPC_OK();
329 : }
330 :
331 : } // namespace dom
332 : } // namespace mozilla
|