Coverage Report

Created: 2018-09-25 14:53

/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