1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "SocketProcessChild.h"
7 #include "SocketProcessLogging.h"
8
9 #include "base/task.h"
10 #include "InputChannelThrottleQueueChild.h"
11 #include "HttpTransactionChild.h"
12 #include "HttpConnectionMgrChild.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/dom/MemoryReportRequest.h"
15 #include "mozilla/ipc/CrashReporterClient.h"
16 #include "mozilla/ipc/BackgroundChild.h"
17 #include "mozilla/ipc/BackgroundParent.h"
18 #include "mozilla/ipc/FileDescriptorSetChild.h"
19 #include "mozilla/ipc/IPCStreamAlloc.h"
20 #include "mozilla/ipc/ProcessChild.h"
21 #include "mozilla/net/AltSvcTransactionChild.h"
22 #include "mozilla/net/BackgroundDataBridgeParent.h"
23 #include "mozilla/net/DNSRequestChild.h"
24 #include "mozilla/net/DNSRequestParent.h"
25 #include "mozilla/net/TRRServiceChild.h"
26 #include "mozilla/ipc/PChildToParentStreamChild.h"
27 #include "mozilla/ipc/PParentToChildStreamChild.h"
28 #include "mozilla/Preferences.h"
29 #include "mozilla/Telemetry.h"
30 #include "nsDebugImpl.h"
31 #include "nsHttpConnectionInfo.h"
32 #include "nsHttpHandler.h"
33 #include "nsIDNSService.h"
34 #include "nsIHttpActivityObserver.h"
35 #include "nsNSSComponent.h"
36 #include "nsThreadManager.h"
37 #include "ProcessUtils.h"
38 #include "SocketProcessBridgeParent.h"
39
40 #if defined(XP_WIN)
41 # include <process.h>
42 #else
43 # include <unistd.h>
44 #endif
45
46 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
47 # include "mozilla/Sandbox.h"
48 #endif
49
50 #ifdef MOZ_GECKO_PROFILER
51 # include "ChildProfilerController.h"
52 #endif
53
54 #ifdef MOZ_WEBRTC
55 # include "mozilla/net/WebrtcTCPSocketChild.h"
56 #endif
57
58 namespace mozilla {
59 namespace net {
60
61 using namespace ipc;
62
63 SocketProcessChild* sSocketProcessChild;
64
SocketProcessChild()65 SocketProcessChild::SocketProcessChild()
66 : mShuttingDown(false), mMutex("SocketProcessChild::mMutex") {
67 LOG(("CONSTRUCT SocketProcessChild::SocketProcessChild\n"));
68 nsDebugImpl::SetMultiprocessMode("Socket");
69
70 MOZ_COUNT_CTOR(SocketProcessChild);
71 sSocketProcessChild = this;
72 }
73
~SocketProcessChild()74 SocketProcessChild::~SocketProcessChild() {
75 LOG(("DESTRUCT SocketProcessChild::SocketProcessChild\n"));
76 MOZ_COUNT_DTOR(SocketProcessChild);
77 sSocketProcessChild = nullptr;
78 }
79
80 /* static */
GetSingleton()81 SocketProcessChild* SocketProcessChild::GetSingleton() {
82 return sSocketProcessChild;
83 }
84
85 #if defined(XP_MACOSX)
86 extern "C" {
87 void CGSShutdownServerConnections();
88 };
89 #endif
90
Init(base::ProcessId aParentPid,const char * aParentBuildID,MessageLoop * aIOLoop,UniquePtr<IPC::Channel> aChannel)91 bool SocketProcessChild::Init(base::ProcessId aParentPid,
92 const char* aParentBuildID, MessageLoop* aIOLoop,
93 UniquePtr<IPC::Channel> aChannel) {
94 if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
95 return false;
96 }
97 if (NS_WARN_IF(!Open(std::move(aChannel), aParentPid, aIOLoop))) {
98 return false;
99 }
100 // This must be sent before any IPDL message, which may hit sentinel
101 // errors due to parent and content processes having different
102 // versions.
103 MessageChannel* channel = GetIPCChannel();
104 if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
105 // We need to quit this process if the buildID doesn't match the parent's.
106 // This can occur when an update occurred in the background.
107 ProcessChild::QuickExit();
108 }
109
110 // Init crash reporter support.
111 CrashReporterClient::InitSingleton(this);
112
113 if (NS_FAILED(NS_InitMinimalXPCOM())) {
114 return false;
115 }
116
117 BackgroundChild::Startup();
118 SetThisProcessName("Socket Process");
119 #if defined(XP_MACOSX)
120 // Close all current connections to the WindowServer. This ensures that the
121 // Activity Monitor will not label the socket process as "Not responding"
122 // because it's not running a native event loop. See bug 1384336.
123 CGSShutdownServerConnections();
124 #endif // XP_MACOSX
125 return true;
126 }
127
ActorDestroy(ActorDestroyReason aWhy)128 void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
129 LOG(("SocketProcessChild::ActorDestroy\n"));
130
131 mShuttingDown = true;
132
133 if (AbnormalShutdown == aWhy) {
134 NS_WARNING("Shutting down Socket process early due to a crash!");
135 ProcessChild::QuickExit();
136 }
137
138 #ifdef MOZ_GECKO_PROFILER
139 if (mProfilerController) {
140 mProfilerController->Shutdown();
141 mProfilerController = nullptr;
142 }
143 #endif
144
145 CrashReporterClient::DestroySingleton();
146 XRE_ShutdownChildProcess();
147 }
148
CleanUp()149 void SocketProcessChild::CleanUp() {
150 LOG(("SocketProcessChild::CleanUp\n"));
151
152 for (auto iter = mSocketProcessBridgeParentMap.Iter(); !iter.Done();
153 iter.Next()) {
154 if (!iter.Data()->Closed()) {
155 iter.Data()->Close();
156 }
157 }
158 NS_ShutdownXPCOM(nullptr);
159 }
160
RecvPreferenceUpdate(const Pref & aPref)161 IPCResult SocketProcessChild::RecvPreferenceUpdate(const Pref& aPref) {
162 Preferences::SetPreference(aPref);
163 return IPC_OK();
164 }
165
RecvRequestMemoryReport(const uint32_t & aGeneration,const bool & aAnonymize,const bool & aMinimizeMemoryUsage,const Maybe<ipc::FileDescriptor> & aDMDFile)166 mozilla::ipc::IPCResult SocketProcessChild::RecvRequestMemoryReport(
167 const uint32_t& aGeneration, const bool& aAnonymize,
168 const bool& aMinimizeMemoryUsage,
169 const Maybe<ipc::FileDescriptor>& aDMDFile) {
170 nsPrintfCString processName("Socket (pid %u)", (unsigned)getpid());
171
172 mozilla::dom::MemoryReportRequestClient::Start(
173 aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
174 [&](const MemoryReport& aReport) {
175 Unused << GetSingleton()->SendAddMemoryReport(aReport);
176 },
177 [&](const uint32_t& aGeneration) {
178 return GetSingleton()->SendFinishMemoryReport(aGeneration);
179 });
180 return IPC_OK();
181 }
182
RecvSetOffline(const bool & aOffline)183 mozilla::ipc::IPCResult SocketProcessChild::RecvSetOffline(
184 const bool& aOffline) {
185 LOG(("SocketProcessChild::RecvSetOffline aOffline=%d\n", aOffline));
186
187 nsCOMPtr<nsIIOService> io(do_GetIOService());
188 NS_ASSERTION(io, "IO Service can not be null");
189
190 io->SetOffline(aOffline);
191
192 return IPC_OK();
193 }
194
RecvInitLinuxSandbox(const Maybe<ipc::FileDescriptor> & aBrokerFd)195 mozilla::ipc::IPCResult SocketProcessChild::RecvInitLinuxSandbox(
196 const Maybe<ipc::FileDescriptor>& aBrokerFd) {
197 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
198 int fd = -1;
199 if (aBrokerFd.isSome()) {
200 fd = aBrokerFd.value().ClonePlatformHandle().release();
201 }
202 SetSocketProcessSandbox(fd);
203 #endif // XP_LINUX && MOZ_SANDBOX
204 return IPC_OK();
205 }
206
RecvInitSocketProcessBridgeParent(const ProcessId & aContentProcessId,Endpoint<mozilla::net::PSocketProcessBridgeParent> && aEndpoint)207 mozilla::ipc::IPCResult SocketProcessChild::RecvInitSocketProcessBridgeParent(
208 const ProcessId& aContentProcessId,
209 Endpoint<mozilla::net::PSocketProcessBridgeParent>&& aEndpoint) {
210 MOZ_ASSERT(NS_IsMainThread());
211 MOZ_ASSERT(!mSocketProcessBridgeParentMap.Get(aContentProcessId, nullptr));
212
213 mSocketProcessBridgeParentMap.Put(
214 aContentProcessId, MakeRefPtr<SocketProcessBridgeParent>(
215 aContentProcessId, std::move(aEndpoint)));
216 return IPC_OK();
217 }
218
RecvInitProfiler(Endpoint<PProfilerChild> && aEndpoint)219 mozilla::ipc::IPCResult SocketProcessChild::RecvInitProfiler(
220 Endpoint<PProfilerChild>&& aEndpoint) {
221 #ifdef MOZ_GECKO_PROFILER
222 mProfilerController =
223 mozilla::ChildProfilerController::Create(std::move(aEndpoint));
224 #endif
225 return IPC_OK();
226 }
227
RecvSocketProcessTelemetryPing()228 mozilla::ipc::IPCResult SocketProcessChild::RecvSocketProcessTelemetryPing() {
229 const uint32_t kExpectedUintValue = 42;
230 Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_SOCKET_ONLY_UINT,
231 kExpectedUintValue);
232 return IPC_OK();
233 }
234
DestroySocketProcessBridgeParent(ProcessId aId)235 void SocketProcessChild::DestroySocketProcessBridgeParent(ProcessId aId) {
236 MOZ_ASSERT(NS_IsMainThread());
237
238 mSocketProcessBridgeParentMap.Remove(aId);
239 }
240
AllocPWebrtcTCPSocketChild(const Maybe<TabId> & tabId)241 PWebrtcTCPSocketChild* SocketProcessChild::AllocPWebrtcTCPSocketChild(
242 const Maybe<TabId>& tabId) {
243 // We don't allocate here: instead we always use IPDL constructor that takes
244 // an existing object
245 MOZ_ASSERT_UNREACHABLE(
246 "AllocPWebrtcTCPSocketChild should not be called on"
247 " socket child");
248 return nullptr;
249 }
250
DeallocPWebrtcTCPSocketChild(PWebrtcTCPSocketChild * aActor)251 bool SocketProcessChild::DeallocPWebrtcTCPSocketChild(
252 PWebrtcTCPSocketChild* aActor) {
253 #ifdef MOZ_WEBRTC
254 WebrtcTCPSocketChild* child = static_cast<WebrtcTCPSocketChild*>(aActor);
255 child->ReleaseIPDLReference();
256 #endif
257 return true;
258 }
259
260 already_AddRefed<PHttpTransactionChild>
AllocPHttpTransactionChild()261 SocketProcessChild::AllocPHttpTransactionChild() {
262 RefPtr<HttpTransactionChild> actor = new HttpTransactionChild();
263 return actor.forget();
264 }
265
AllocPFileDescriptorSetChild(const FileDescriptor & aFD)266 PFileDescriptorSetChild* SocketProcessChild::AllocPFileDescriptorSetChild(
267 const FileDescriptor& aFD) {
268 return new FileDescriptorSetChild(aFD);
269 }
270
DeallocPFileDescriptorSetChild(PFileDescriptorSetChild * aActor)271 bool SocketProcessChild::DeallocPFileDescriptorSetChild(
272 PFileDescriptorSetChild* aActor) {
273 delete aActor;
274 return true;
275 }
276
277 PChildToParentStreamChild*
AllocPChildToParentStreamChild()278 SocketProcessChild::AllocPChildToParentStreamChild() {
279 MOZ_CRASH("PChildToParentStreamChild actors should be manually constructed!");
280 }
281
DeallocPChildToParentStreamChild(PChildToParentStreamChild * aActor)282 bool SocketProcessChild::DeallocPChildToParentStreamChild(
283 PChildToParentStreamChild* aActor) {
284 delete aActor;
285 return true;
286 }
287
288 PParentToChildStreamChild*
AllocPParentToChildStreamChild()289 SocketProcessChild::AllocPParentToChildStreamChild() {
290 return mozilla::ipc::AllocPParentToChildStreamChild();
291 }
292
DeallocPParentToChildStreamChild(PParentToChildStreamChild * aActor)293 bool SocketProcessChild::DeallocPParentToChildStreamChild(
294 PParentToChildStreamChild* aActor) {
295 delete aActor;
296 return true;
297 }
298
299 PChildToParentStreamChild*
SendPChildToParentStreamConstructor(PChildToParentStreamChild * aActor)300 SocketProcessChild::SendPChildToParentStreamConstructor(
301 PChildToParentStreamChild* aActor) {
302 MOZ_ASSERT(NS_IsMainThread());
303 return PSocketProcessChild::SendPChildToParentStreamConstructor(aActor);
304 }
305
SendPFileDescriptorSetConstructor(const FileDescriptor & aFD)306 PFileDescriptorSetChild* SocketProcessChild::SendPFileDescriptorSetConstructor(
307 const FileDescriptor& aFD) {
308 MOZ_ASSERT(NS_IsMainThread());
309 return PSocketProcessChild::SendPFileDescriptorSetConstructor(aFD);
310 }
311
312 already_AddRefed<PHttpConnectionMgrChild>
AllocPHttpConnectionMgrChild()313 SocketProcessChild::AllocPHttpConnectionMgrChild() {
314 LOG(("SocketProcessChild::AllocPHttpConnectionMgrChild \n"));
315 if (!gHttpHandler) {
316 nsresult rv;
317 nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
318 if (NS_FAILED(rv)) {
319 return nullptr;
320 }
321
322 nsCOMPtr<nsIProtocolHandler> handler;
323 rv = ios->GetProtocolHandler("http", getter_AddRefs(handler));
324 if (NS_FAILED(rv)) {
325 return nullptr;
326 }
327
328 // Initialize DNS Service here, since it needs to be done in main thread.
329 nsCOMPtr<nsIDNSService> dns =
330 do_GetService("@mozilla.org/network/dns-service;1", &rv);
331 if (NS_FAILED(rv)) {
332 return nullptr;
333 }
334
335 RefPtr<HttpConnectionMgrChild> actor = new HttpConnectionMgrChild();
336 return actor.forget();
337 }
338
339 return nullptr;
340 }
341
342 mozilla::ipc::IPCResult
RecvOnHttpActivityDistributorActivated(const bool & aIsActivated)343 SocketProcessChild::RecvOnHttpActivityDistributorActivated(
344 const bool& aIsActivated) {
345 if (nsCOMPtr<nsIHttpActivityObserver> distributor =
346 services::GetActivityDistributor()) {
347 distributor->SetIsActive(aIsActivated);
348 }
349 return IPC_OK();
350 }
351 already_AddRefed<PInputChannelThrottleQueueChild>
AllocPInputChannelThrottleQueueChild(const uint32_t & aMeanBytesPerSecond,const uint32_t & aMaxBytesPerSecond)352 SocketProcessChild::AllocPInputChannelThrottleQueueChild(
353 const uint32_t& aMeanBytesPerSecond, const uint32_t& aMaxBytesPerSecond) {
354 RefPtr<InputChannelThrottleQueueChild> p =
355 new InputChannelThrottleQueueChild();
356 p->Init(aMeanBytesPerSecond, aMaxBytesPerSecond);
357 return p.forget();
358 }
359
360 already_AddRefed<PAltSvcTransactionChild>
AllocPAltSvcTransactionChild(const HttpConnectionInfoCloneArgs & aConnInfo,const uint32_t & aCaps)361 SocketProcessChild::AllocPAltSvcTransactionChild(
362 const HttpConnectionInfoCloneArgs& aConnInfo, const uint32_t& aCaps) {
363 RefPtr<nsHttpConnectionInfo> cinfo =
364 nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(aConnInfo);
365 RefPtr<AltSvcTransactionChild> child =
366 new AltSvcTransactionChild(cinfo, aCaps);
367 return child.forget();
368 }
369
AllocPDNSRequestChild(const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)370 already_AddRefed<PDNSRequestChild> SocketProcessChild::AllocPDNSRequestChild(
371 const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType,
372 const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
373 RefPtr<DNSRequestHandler> handler = new DNSRequestHandler();
374 RefPtr<DNSRequestChild> actor = new DNSRequestChild(handler);
375 return actor.forget();
376 }
377
RecvPDNSRequestConstructor(PDNSRequestChild * aActor,const nsCString & aHost,const nsCString & aTrrServer,const uint16_t & aType,const OriginAttributes & aOriginAttributes,const uint32_t & aFlags)378 mozilla::ipc::IPCResult SocketProcessChild::RecvPDNSRequestConstructor(
379 PDNSRequestChild* aActor, const nsCString& aHost,
380 const nsCString& aTrrServer, const uint16_t& aType,
381 const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) {
382 RefPtr<DNSRequestChild> actor = static_cast<DNSRequestChild*>(aActor);
383 RefPtr<DNSRequestHandler> handler =
384 actor->GetDNSRequest()->AsDNSRequestHandler();
385 handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags);
386 return IPC_OK();
387 }
388
AddDataBridgeToMap(uint64_t aChannelId,BackgroundDataBridgeParent * aActor)389 void SocketProcessChild::AddDataBridgeToMap(
390 uint64_t aChannelId, BackgroundDataBridgeParent* aActor) {
391 ipc::AssertIsOnBackgroundThread();
392 MutexAutoLock lock(mMutex);
393 mBackgroundDataBridgeMap.Put(aChannelId, aActor);
394 }
395
RemoveDataBridgeFromMap(uint64_t aChannelId)396 void SocketProcessChild::RemoveDataBridgeFromMap(uint64_t aChannelId) {
397 ipc::AssertIsOnBackgroundThread();
398 MutexAutoLock lock(mMutex);
399 mBackgroundDataBridgeMap.Remove(aChannelId);
400 }
401
402 Maybe<RefPtr<BackgroundDataBridgeParent>>
GetAndRemoveDataBridge(uint64_t aChannelId)403 SocketProcessChild::GetAndRemoveDataBridge(uint64_t aChannelId) {
404 MutexAutoLock lock(mMutex);
405 return mBackgroundDataBridgeMap.GetAndRemove(aChannelId);
406 }
407
RecvClearSessionCache()408 mozilla::ipc::IPCResult SocketProcessChild::RecvClearSessionCache() {
409 if (EnsureNSSInitializedChromeOrContent()) {
410 nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
411 }
412 return IPC_OK();
413 }
414
AllocPTRRServiceChild(const bool & aCaptiveIsPassed,const bool & aParentalControlEnabled,const nsTArray<nsCString> & aDNSSuffixList)415 already_AddRefed<PTRRServiceChild> SocketProcessChild::AllocPTRRServiceChild(
416 const bool& aCaptiveIsPassed, const bool& aParentalControlEnabled,
417 const nsTArray<nsCString>& aDNSSuffixList) {
418 RefPtr<TRRServiceChild> actor = new TRRServiceChild();
419 return actor.forget();
420 }
421
RecvPTRRServiceConstructor(PTRRServiceChild * aActor,const bool & aCaptiveIsPassed,const bool & aParentalControlEnabled,nsTArray<nsCString> && aDNSSuffixList)422 mozilla::ipc::IPCResult SocketProcessChild::RecvPTRRServiceConstructor(
423 PTRRServiceChild* aActor, const bool& aCaptiveIsPassed,
424 const bool& aParentalControlEnabled, nsTArray<nsCString>&& aDNSSuffixList) {
425 static_cast<TRRServiceChild*>(aActor)->Init(
426 aCaptiveIsPassed, aParentalControlEnabled, std::move(aDNSSuffixList));
427 return IPC_OK();
428 }
429
430 } // namespace net
431 } // namespace mozilla
432