Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/GeckoChildProcessHost.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
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "GeckoChildProcessHost.h"
8
9
#include "base/command_line.h"
10
#include "base/string_util.h"
11
#include "base/task.h"
12
#include "chrome/common/chrome_switches.h"
13
#include "chrome/common/process_watcher.h"
14
#ifdef MOZ_WIDGET_COCOA
15
#include "chrome/common/mach_ipc_mac.h"
16
#include "base/rand_util.h"
17
#include "nsILocalFileMac.h"
18
#include "SharedMemoryBasic.h"
19
#endif
20
21
#include "MainThreadUtils.h"
22
#include "mozilla/Sprintf.h"
23
#include "prenv.h"
24
#include "nsXPCOMPrivate.h"
25
26
#if defined(MOZ_CONTENT_SANDBOX)
27
#include "mozilla/SandboxSettings.h"
28
#include "nsAppDirectoryServiceDefs.h"
29
#endif
30
31
#include "nsExceptionHandler.h"
32
33
#include "nsDirectoryServiceDefs.h"
34
#include "nsIFile.h"
35
#include "nsPrintfCString.h"
36
37
#include "mozilla/ClearOnShutdown.h"
38
#include "mozilla/ipc/BrowserProcessSubThread.h"
39
#include "mozilla/ipc/EnvironmentMap.h"
40
#include "mozilla/Omnijar.h"
41
#include "mozilla/Telemetry.h"
42
#include "ProtocolUtils.h"
43
#include <sys/stat.h>
44
45
#ifdef XP_WIN
46
#include "nsIWinTaskbar.h"
47
#include <stdlib.h>
48
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
49
50
#if defined(MOZ_SANDBOX)
51
#include "mozilla/Preferences.h"
52
#include "mozilla/sandboxing/sandboxLogging.h"
53
#include "WinUtils.h"
54
#endif
55
#endif
56
57
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
58
#include "mozilla/SandboxLaunch.h"
59
#endif
60
61
#include "nsTArray.h"
62
#include "nsClassHashtable.h"
63
#include "nsHashKeys.h"
64
#include "nsNativeCharsetUtils.h"
65
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
66
#include "private/pprio.h"
67
68
using mozilla::MonitorAutoLock;
69
using mozilla::ipc::GeckoChildProcessHost;
70
71
#ifdef MOZ_WIDGET_ANDROID
72
#include "AndroidBridge.h"
73
#include "GeneratedJNIWrappers.h"
74
#include "mozilla/jni/Refs.h"
75
#include "mozilla/jni/Utils.h"
76
#endif
77
78
static bool
79
ShouldHaveDirectoryService()
80
0
{
81
0
  return GeckoProcessType_Default == XRE_GetProcessType();
82
0
}
83
84
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
85
                                             bool aIsFileContent)
86
  : mProcessType(aProcessType),
87
    mIsFileContent(aIsFileContent),
88
    mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
89
    mLaunchOptions(MakeUnique<base::LaunchOptions>()),
90
    mProcessState(CREATING_CHANNEL),
91
#ifdef XP_WIN
92
    mGroupId(u"-"),
93
#endif
94
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
95
    mEnableSandboxLogging(false),
96
    mSandboxLevel(0),
97
#endif
98
    mChildProcessHandle(0)
99
#if defined(MOZ_WIDGET_COCOA)
100
  , mChildTask(MACH_PORT_NULL)
101
#endif
102
0
{
103
0
    MOZ_COUNT_CTOR(GeckoChildProcessHost);
104
0
}
105
106
GeckoChildProcessHost::~GeckoChildProcessHost()
107
108
0
{
109
0
  AssertIOThread();
110
0
111
0
  MOZ_COUNT_DTOR(GeckoChildProcessHost);
112
0
113
0
  if (mChildProcessHandle != 0) {
114
#if defined(MOZ_WIDGET_COCOA)
115
    SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
116
#endif
117
    ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
118
#ifdef NS_FREE_PERMANENT_DATA
119
    // If we're doing leak logging, shutdown can be slow.
120
                                            , false // don't "force"
121
#endif
122
    );
123
0
  }
124
0
125
#if defined(MOZ_WIDGET_COCOA)
126
  if (mChildTask != MACH_PORT_NULL)
127
    mach_port_deallocate(mach_task_self(), mChildTask);
128
#endif
129
130
0
  if (mChildProcessHandle != 0) {
131
#if defined(XP_WIN)
132
    CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
133
      base::GetProcId(mChildProcessHandle));
134
#else
135
    CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
136
0
      mChildProcessHandle);
137
0
#endif
138
0
  }
139
0
}
140
141
//static
142
auto
143
GeckoChildProcessHost::GetPathToBinary(FilePath& exePath, GeckoProcessType processType) -> BinaryPathType
144
0
{
145
0
  if (sRunSelfAsContentProc &&
146
0
      (processType == GeckoProcessType_Content || processType == GeckoProcessType_GPU ||
147
0
       processType == GeckoProcessType_VR)) {
148
#if defined(OS_WIN)
149
    wchar_t exePathBuf[MAXPATHLEN];
150
    if (!::GetModuleFileNameW(nullptr, exePathBuf, MAXPATHLEN)) {
151
      MOZ_CRASH("GetModuleFileNameW failed (FIXME)");
152
    }
153
#if defined(MOZ_SANDBOX)
154
    // We need to start the child process using the real path, so that the
155
    // sandbox policy rules will match for DLLs loaded from the bin dir after
156
    // we have lowered the sandbox.
157
    std::wstring exePathStr = exePathBuf;
158
    if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(exePathStr)) {
159
      exePath = FilePath::FromWStringHack(exePathStr);
160
    } else
161
#endif
162
    {
163
      exePath = FilePath::FromWStringHack(exePathBuf);
164
    }
165
#elif defined(OS_POSIX)
166
    exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
167
#else
168
#  error Sorry; target OS not supported yet.
169
#endif
170
    return BinaryPathType::Self;
171
0
  }
172
0
173
0
  if (ShouldHaveDirectoryService()) {
174
0
    MOZ_ASSERT(gGREBinPath);
175
#ifdef OS_WIN
176
    exePath = FilePath(char16ptr_t(gGREBinPath));
177
#elif MOZ_WIDGET_COCOA
178
    nsCOMPtr<nsIFile> childProcPath;
179
    NS_NewLocalFile(nsDependentString(gGREBinPath), false,
180
                    getter_AddRefs(childProcPath));
181
182
    // We need to use an App Bundle on OS X so that we can hide
183
    // the dock icon. See Bug 557225.
184
    childProcPath->AppendNative(NS_LITERAL_CSTRING("plugin-container.app"));
185
    childProcPath->AppendNative(NS_LITERAL_CSTRING("Contents"));
186
    childProcPath->AppendNative(NS_LITERAL_CSTRING("MacOS"));
187
    nsCString tempCPath;
188
    childProcPath->GetNativePath(tempCPath);
189
    exePath = FilePath(tempCPath.get());
190
#else
191
    nsCString path;
192
0
    NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
193
0
    exePath = FilePath(path.get());
194
0
#endif
195
0
  }
196
0
197
0
  if (exePath.empty()) {
198
#ifdef OS_WIN
199
    exePath = FilePath::FromWStringHack(CommandLine::ForCurrentProcess()->program());
200
#else
201
    exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
202
0
#endif
203
0
    exePath = exePath.DirName();
204
0
  }
205
0
206
0
  exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
207
0
208
0
  return BinaryPathType::PluginContainer;
209
0
}
210
211
#ifdef MOZ_WIDGET_COCOA
212
class AutoCFTypeObject {
213
public:
214
  explicit AutoCFTypeObject(CFTypeRef object)
215
  {
216
    mObject = object;
217
  }
218
  ~AutoCFTypeObject()
219
  {
220
    ::CFRelease(mObject);
221
  }
222
private:
223
  CFTypeRef mObject;
224
};
225
#endif
226
227
// We start the unique IDs at 1 so that 0 can be used to mean that
228
// a component has no unique ID assigned to it.
229
uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
230
231
/* static */
232
uint32_t
233
GeckoChildProcessHost::GetUniqueID()
234
0
{
235
0
  return sNextUniqueID++;
236
0
}
237
238
void
239
GeckoChildProcessHost::PrepareLaunch()
240
0
{
241
0
  if (CrashReporter::GetEnabled()) {
242
0
    CrashReporter::OOPInit();
243
0
  }
244
0
245
0
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
246
0
  SandboxLaunchPrepare(mProcessType, mLaunchOptions.get());
247
0
#endif
248
0
249
#ifdef XP_WIN
250
  if (mProcessType == GeckoProcessType_Plugin) {
251
    InitWindowsGroupID();
252
  }
253
254
#if defined(MOZ_CONTENT_SANDBOX)
255
  // We need to get the pref here as the process is launched off main thread.
256
  if (mProcessType == GeckoProcessType_Content) {
257
    mSandboxLevel = GetEffectiveContentSandboxLevel();
258
    mEnableSandboxLogging =
259
      Preferences::GetBool("security.sandbox.logging.enabled");
260
261
    // We currently have to whitelist certain paths for tests to work in some
262
    // development configurations.
263
    nsAutoString readPaths;
264
    nsresult rv =
265
      Preferences::GetString("security.sandbox.content.read_path_whitelist",
266
                             readPaths);
267
    if (NS_SUCCEEDED(rv)) {
268
      for (const nsAString& readPath : readPaths.Split(',')) {
269
        nsString trimmedPath(readPath);
270
        trimmedPath.Trim(" ", true, true);
271
        std::wstring resolvedPath(trimmedPath.Data());
272
        // Before resolving check if path ends with '\' as this indicates we
273
        // want to give read access to a directory and so it needs a wildcard.
274
        bool addWildcard = (resolvedPath.back() == L'\\');
275
        if (!widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
276
          NS_ERROR("Failed to resolve test read policy rule.");
277
          continue;
278
        }
279
280
        if (addWildcard) {
281
          resolvedPath.append(L"\\*");
282
        }
283
        mAllowedFilesRead.push_back(resolvedPath);
284
      }
285
    }
286
  }
287
#endif
288
289
#if defined(MOZ_SANDBOX)
290
  // For other process types we can't rely on them being launched on main
291
  // thread and they may not have access to prefs in the child process, so allow
292
  // them to turn on logging via an environment variable.
293
  mEnableSandboxLogging = mEnableSandboxLogging
294
                          || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
295
#endif
296
#elif defined(XP_LINUX)
297
#if defined(MOZ_CONTENT_SANDBOX)
298
0
  // Get and remember the path to the per-content-process tmpdir
299
0
  if (ShouldHaveDirectoryService()) {
300
0
    nsCOMPtr<nsIFile> contentTempDir;
301
0
    nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
302
0
                                         getter_AddRefs(contentTempDir));
303
0
    if (NS_SUCCEEDED(rv)) {
304
0
      contentTempDir->GetNativePath(mTmpDirName);
305
0
    }
306
0
  }
307
0
#endif
308
0
#endif
309
0
}
310
311
#ifdef XP_WIN
312
void GeckoChildProcessHost::InitWindowsGroupID()
313
{
314
  // On Win7+, pass the application user model to the child, so it can
315
  // register with it. This insures windows created by the container
316
  // properly group with the parent app on the Win7 taskbar.
317
  nsCOMPtr<nsIWinTaskbar> taskbarInfo =
318
    do_GetService(NS_TASKBAR_CONTRACTID);
319
  if (taskbarInfo) {
320
    bool isSupported = false;
321
    taskbarInfo->GetAvailable(&isSupported);
322
    nsAutoString appId;
323
    if (isSupported && NS_SUCCEEDED(taskbarInfo->GetDefaultGroupId(appId))) {
324
      MOZ_ASSERT(mGroupId.EqualsLiteral("-"));
325
      mGroupId.Assign(appId);
326
    }
327
  }
328
}
329
#endif
330
331
bool
332
GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs)
333
0
{
334
0
  if (!AsyncLaunch(std::move(aExtraOpts))) {
335
0
    return false;
336
0
  }
337
0
  return WaitUntilConnected(aTimeoutMs);
338
0
}
339
340
bool
341
GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
342
0
{
343
0
  PrepareLaunch();
344
0
345
0
  MessageLoop* ioLoop = XRE_GetIOMessageLoop();
346
0
347
0
  // Currently this can't fail (see the MOZ_ALWAYS_SUCCEEDS in
348
0
  // MessageLoop::PostTask_Helper), but in the future it possibly
349
0
  // could, in which case this method could return false.
350
0
  ioLoop->PostTask(NewNonOwningRunnableMethod<std::vector<std::string>>(
351
0
    "ipc::GeckoChildProcessHost::RunPerformAsyncLaunch",
352
0
    this,
353
0
    &GeckoChildProcessHost::RunPerformAsyncLaunch,
354
0
    aExtraOpts));
355
0
356
0
  return true;
357
0
}
358
359
bool
360
GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
361
0
{
362
0
  AUTO_PROFILER_LABEL("GeckoChildProcessHost::WaitUntilConnected", OTHER);
363
0
364
0
  // NB: this uses a different mechanism than the chromium parent
365
0
  // class.
366
0
  TimeDuration timeout = (aTimeoutMs > 0) ?
367
0
    TimeDuration::FromMilliseconds(aTimeoutMs) : TimeDuration::Forever();
368
0
369
0
  MonitorAutoLock lock(mMonitor);
370
0
  TimeStamp waitStart = TimeStamp::Now();
371
0
  TimeStamp current;
372
0
373
0
  // We'll receive several notifications, we need to exit when we
374
0
  // have either successfully launched or have timed out.
375
0
  while (mProcessState != PROCESS_CONNECTED) {
376
0
    // If there was an error then return it, don't wait out the timeout.
377
0
    if (mProcessState == PROCESS_ERROR) {
378
0
      break;
379
0
    }
380
0
381
0
    CVStatus status = lock.Wait(timeout);
382
0
    if (status == CVStatus::Timeout) {
383
0
      break;
384
0
    }
385
0
386
0
    if (timeout != TimeDuration::Forever()) {
387
0
      current = TimeStamp::Now();
388
0
      timeout -= current - waitStart;
389
0
      waitStart = current;
390
0
    }
391
0
  }
392
0
393
0
  return mProcessState == PROCESS_CONNECTED;
394
0
}
395
396
bool
397
GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts)
398
0
{
399
0
  if (!AsyncLaunch(std::move(aExtraOpts))) {
400
0
    return false;
401
0
  }
402
0
403
0
  MonitorAutoLock lock(mMonitor);
404
0
  while (mProcessState < PROCESS_CREATED) {
405
0
    lock.Wait();
406
0
  }
407
0
  MOZ_ASSERT(mProcessState == PROCESS_ERROR || mChildProcessHandle);
408
0
409
0
  return mProcessState < PROCESS_ERROR;
410
0
}
411
412
void
413
GeckoChildProcessHost::InitializeChannel()
414
0
{
415
0
  CreateChannel();
416
0
417
0
  MonitorAutoLock lock(mMonitor);
418
0
  mProcessState = CHANNEL_INITIALIZED;
419
0
  lock.Notify();
420
0
}
421
422
void
423
GeckoChildProcessHost::Join()
424
0
{
425
0
  AssertIOThread();
426
0
427
0
  if (!mChildProcessHandle) {
428
0
    return;
429
0
  }
430
0
431
0
  // If this fails, there's nothing we can do.
432
0
  base::KillProcess(mChildProcessHandle, 0, /*wait*/true);
433
0
  SetAlreadyDead();
434
0
}
435
436
void
437
GeckoChildProcessHost::SetAlreadyDead()
438
0
{
439
0
  if (mChildProcessHandle &&
440
0
      mChildProcessHandle != kInvalidProcessHandle) {
441
0
    base::CloseProcessHandle(mChildProcessHandle);
442
0
  }
443
0
444
0
  mChildProcessHandle = 0;
445
0
}
446
447
int32_t GeckoChildProcessHost::mChildCounter = 0;
448
449
void
450
GeckoChildProcessHost::GetChildLogName(const char* origLogName,
451
                                       nsACString &buffer)
452
0
{
453
#ifdef XP_WIN
454
  // On Windows we must expand relative paths because sandboxing rules
455
  // bound only to full paths.  fopen fowards to NtCreateFile which checks
456
  // the path against the sanboxing rules as passed to fopen (left relative).
457
  char absPath[MAX_PATH + 2];
458
  if (_fullpath(absPath, origLogName, sizeof(absPath))) {
459
#ifdef MOZ_SANDBOX
460
    // We need to make sure the child log name doesn't contain any junction
461
    // points or symlinks or the sandbox will reject rules to allow writing.
462
    std::wstring resolvedPath(NS_ConvertUTF8toUTF16(absPath).get());
463
    if (widget::WinUtils::ResolveJunctionPointsAndSymLinks(resolvedPath)) {
464
      AppendUTF16toUTF8(
465
        MakeSpan(reinterpret_cast<const char16_t*>(resolvedPath.data()),
466
                 resolvedPath.size()),
467
        buffer);
468
    } else
469
#endif
470
    {
471
      buffer.Append(absPath);
472
    }
473
  } else
474
#endif
475
  {
476
0
    buffer.Append(origLogName);
477
0
  }
478
0
479
0
  // Append child-specific postfix to name
480
0
  buffer.AppendLiteral(".child-");
481
0
  buffer.AppendInt(mChildCounter);
482
0
}
483
484
bool
485
GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts)
486
0
{
487
0
  InitializeChannel();
488
0
489
0
  bool ok = PerformAsyncLaunch(aExtraOpts);
490
0
  if (!ok) {
491
0
    // WaitUntilConnected might be waiting for us to signal.
492
0
    // If something failed let's set the error state and notify.
493
0
    MonitorAutoLock lock(mMonitor);
494
0
    mProcessState = PROCESS_ERROR;
495
0
    lock.Notify();
496
#ifdef ASYNC_CONTENTPROC_LAUNCH
497
    OnProcessLaunchError();
498
#endif
499
0
    CHROMIUM_LOG(ERROR) << "Failed to launch " <<
500
0
      XRE_ChildProcessTypeToString(mProcessType) << " subprocess";
501
0
    Telemetry::Accumulate(Telemetry::SUBPROCESS_LAUNCH_FAILURE,
502
0
      nsDependentCString(XRE_ChildProcessTypeToString(mProcessType)));
503
#ifdef ASYNC_CONTENTPROC_LAUNCH
504
  } else {
505
    OnProcessHandleReady(mChildProcessHandle);
506
#endif
507
  }
508
0
  return ok;
509
0
}
510
511
void
512
#if defined(XP_WIN)
513
AddAppDirToCommandLine(CommandLine& aCmdLine)
514
#else
515
AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
516
#endif
517
0
{
518
0
  // Content processes need access to application resources, so pass
519
0
  // the full application directory path to the child process.
520
0
  if (ShouldHaveDirectoryService()) {
521
0
    nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
522
0
    NS_ASSERTION(directoryService, "Expected XPCOM to be available");
523
0
    if (directoryService) {
524
0
      nsCOMPtr<nsIFile> appDir;
525
0
      // NS_XPCOM_CURRENT_PROCESS_DIR really means the app dir, not the
526
0
      // current process dir.
527
0
      nsresult rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
528
0
                                          NS_GET_IID(nsIFile),
529
0
                                          getter_AddRefs(appDir));
530
0
      if (NS_SUCCEEDED(rv)) {
531
#if defined(XP_WIN)
532
        nsString path;
533
        MOZ_ALWAYS_SUCCEEDS(appDir->GetPath(path));
534
        aCmdLine.AppendLooseValue(UTF8ToWide("-appdir"));
535
        std::wstring wpath(path.get());
536
        aCmdLine.AppendLooseValue(wpath);
537
#else
538
        nsAutoCString path;
539
0
        MOZ_ALWAYS_SUCCEEDS(appDir->GetNativePath(path));
540
0
        aCmdLine.push_back("-appdir");
541
0
        aCmdLine.push_back(path.get());
542
0
#endif
543
0
      }
544
0
545
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
546
      // Full path to the profile dir
547
      nsCOMPtr<nsIFile> profileDir;
548
      rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
549
                                 NS_GET_IID(nsIFile),
550
                                 getter_AddRefs(profileDir));
551
      if (NS_SUCCEEDED(rv)) {
552
        nsAutoCString path;
553
        MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
554
        aCmdLine.push_back("-profile");
555
        aCmdLine.push_back(path.get());
556
      }
557
#endif
558
    }
559
0
  }
560
0
}
561
562
bool
563
GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
564
0
{
565
0
#ifdef MOZ_GECKO_PROFILER
566
0
  AutoSetProfilerEnvVarsForChildProcess profilerEnvironment;
567
0
#endif
568
0
569
0
  // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
570
0
  //   or mChildCounter touched by any other thread, so this is safe.
571
0
  ++mChildCounter;
572
0
573
0
  const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
574
0
  const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
575
0
576
0
  if (origNSPRLogName) {
577
0
    nsAutoCString nsprLogName;
578
0
    GetChildLogName(origNSPRLogName, nsprLogName);
579
0
    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("NSPR_LOG_FILE")]
580
0
        = ENVIRONMENT_STRING(nsprLogName);
581
0
  }
582
0
  if (origMozLogName) {
583
0
    nsAutoCString mozLogName;
584
0
    GetChildLogName(origMozLogName, mozLogName);
585
0
    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MOZ_LOG_FILE")]
586
0
        = ENVIRONMENT_STRING(mozLogName);
587
0
  }
588
0
589
0
  // `RUST_LOG_CHILD` is meant for logging child processes only.
590
0
  nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
591
0
  if (!childRustLog.IsEmpty()) {
592
0
    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")]
593
0
        = ENVIRONMENT_STRING(childRustLog);
594
0
  }
595
0
596
0
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
597
0
  if (!mTmpDirName.IsEmpty()) {
598
0
    // Point a bunch of things that might want to write from content to our
599
0
    // shiny new content-process specific tmpdir
600
0
    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
601
0
      ENVIRONMENT_STRING(mTmpDirName);
602
0
    // Partial fix for bug 1380051 (not persistent - should be)
603
0
    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
604
0
      ENVIRONMENT_STRING(mTmpDirName);
605
0
  }
606
0
#endif
607
0
608
0
  // We rely on the fact that InitializeChannel() has already been processed
609
0
  // on the IO thread before this point is reached.
610
0
  if (!GetChannel()) {
611
0
    return false;
612
0
  }
613
0
614
0
  base::ProcessHandle process = 0;
615
0
616
0
  // send the child the PID so that it can open a ProcessHandle back to us.
617
0
  // probably don't want to do this in the long run
618
0
  char pidstring[32];
619
0
  SprintfLiteral(pidstring, "%d", base::GetCurrentProcId());
620
0
621
0
  const char* const childProcessType =
622
0
      XRE_ChildProcessTypeToString(mProcessType);
623
0
624
0
  PRFileDesc* crashAnnotationReadPipe;
625
0
  PRFileDesc* crashAnnotationWritePipe;
626
0
  if (PR_CreatePipe(&crashAnnotationReadPipe, &crashAnnotationWritePipe) != PR_SUCCESS) {
627
0
    return false;
628
0
  }
629
0
630
0
//--------------------------------------------------
631
0
#if defined(OS_POSIX)
632
0
  // For POSIX, we have to be extremely anal about *not* using
633
0
  // std::wstring in code compiled with Mozilla's -fshort-wchar
634
0
  // configuration, because chromium is compiled with -fno-short-wchar
635
0
  // and passing wstrings from one config to the other is unsafe.  So
636
0
  // we split the logic here.
637
0
638
0
# if defined(OS_POSIX)
639
0
#  if defined(MOZ_WIDGET_GTK)
640
0
  if (mProcessType == GeckoProcessType_Content) {
641
0
    // disable IM module to avoid sandbox violation
642
0
    mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
643
0
644
0
    // Disable ATK accessibility code in content processes because it conflicts
645
0
    // with the sandbox, and we proxy that information through the main process
646
0
    // anyway.
647
0
    mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
648
0
  }
649
0
#  endif // defined(MOZ_WIDGET_GTK)
650
0
651
0
  // XPCOM may not be initialized in some subprocesses.  We don't want
652
0
  // to initialize XPCOM just for the directory service, especially
653
0
  // since LD_LIBRARY_PATH is already set correctly in subprocesses
654
0
  // (meaning that we don't need to set that up in the environment).
655
0
  if (ShouldHaveDirectoryService()) {
656
0
    MOZ_ASSERT(gGREBinPath);
657
0
    nsCString path;
658
0
    NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
659
0
#  if defined(OS_LINUX) || defined(OS_BSD)
660
0
    const char *ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
661
0
    nsCString new_ld_lib_path(path.get());
662
0
663
0
#   ifdef MOZ_WIDGET_GTK
664
0
    if (mProcessType == GeckoProcessType_Plugin) {
665
0
      new_ld_lib_path.AppendLiteral("/gtk2:");
666
0
      new_ld_lib_path.Append(path.get());
667
0
    }
668
0
#   endif // MOZ_WIDGET_GTK
669
0
    if (ld_library_path && *ld_library_path) {
670
0
      new_ld_lib_path.Append(':');
671
0
      new_ld_lib_path.Append(ld_library_path);
672
0
    }
673
0
    mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
674
0
675
#  elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
676
    mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = path.get();
677
    // XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
678
    //     process, and has no effect on other subprocesses (the hooks in
679
    //     libplugin_child_interpose.dylib become noops).  But currently it
680
    //     gets set when launching any kind of subprocess.
681
    //
682
    // Trigger "dyld interposing" for the dylib that contains
683
    // plugin_child_interpose.mm.  This allows us to hook OS calls in the
684
    // plugin process (ones that don't work correctly in a background
685
    // process).  Don't break any other "dyld interposing" that has already
686
    // been set up by whatever may have launched the browser.
687
    const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
688
    nsCString interpose;
689
    if (prevInterpose && strlen(prevInterpose) > 0) {
690
      interpose.Assign(prevInterpose);
691
      interpose.Append(':');
692
    }
693
    interpose.Append(path.get());
694
    interpose.AppendLiteral("/libplugin_child_interpose.dylib");
695
    mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose.get();
696
#  endif // defined(OS_LINUX) || defined(OS_BSD)
697
  }
698
0
# endif // defined(OS_POSIX)
699
0
700
0
  FilePath exePath;
701
0
  BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
702
0
703
0
  // remap the IPC socket fd to a well-known int, as the OS does for
704
0
  // STDOUT_FILENO, for example
705
0
  int srcChannelFd, dstChannelFd;
706
0
  channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
707
0
  mLaunchOptions->fds_to_remap
708
0
    .push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
709
0
710
0
  // no need for kProcessChannelID, the child process inherits the
711
0
  // other end of the socketpair() from us
712
0
713
0
  std::vector<std::string> childArgv;
714
0
715
0
  childArgv.push_back(exePath.value());
716
0
717
0
  if (pathType == BinaryPathType::Self) {
718
0
    childArgv.push_back("-contentproc");
719
0
  }
720
0
721
0
  childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end());
722
0
723
0
  if (Omnijar::IsInitialized()) {
724
0
    // Make sure that child processes can find the omnijar
725
0
    // See XRE_InitCommandLine in nsAppRunner.cpp
726
0
    nsAutoCString path;
727
0
    nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
728
0
    if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
729
0
      childArgv.push_back("-greomni");
730
0
      childArgv.push_back(path.get());
731
0
    }
732
0
    file = Omnijar::GetPath(Omnijar::APP);
733
0
    if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
734
0
      childArgv.push_back("-appomni");
735
0
      childArgv.push_back(path.get());
736
0
    }
737
0
  }
738
0
739
0
  // Add the application directory path (-appdir path)
740
0
  AddAppDirToCommandLine(childArgv);
741
0
742
0
  // Tmp dir that the GPU process should use for crash reports. This arg is
743
0
  // always populated (but possibly with an empty value) for a GPU child process.
744
0
  if (mProcessType == GeckoProcessType_GPU || mProcessType == GeckoProcessType_VR) {
745
0
    nsCOMPtr<nsIFile> file;
746
0
    CrashReporter::GetChildProcessTmpDir(getter_AddRefs(file));
747
0
    nsAutoCString path;
748
0
    if (file) {
749
0
      file->GetNativePath(path);
750
0
    }
751
0
    childArgv.push_back(path.get());
752
0
  }
753
0
754
0
  childArgv.push_back(pidstring);
755
0
756
0
  if (!CrashReporter::IsDummy()) {
757
0
#if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
758
0
    int childCrashFd, childCrashRemapFd;
759
0
    if (!CrashReporter::CreateNotificationPipeForChild(&childCrashFd,
760
0
                                                       &childCrashRemapFd)) {
761
0
      return false;
762
0
    }
763
0
764
0
    if (0 <= childCrashFd) {
765
0
      mLaunchOptions->fds_to_remap
766
0
        .push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
767
0
      // "true" == crash reporting enabled
768
0
      childArgv.push_back("true");
769
0
    } else {
770
0
      // "false" == crash reporting disabled
771
0
      childArgv.push_back("false");
772
0
    }
773
#elif defined(MOZ_WIDGET_COCOA) // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
774
    childArgv.push_back(CrashReporter::GetChildNotificationPipe());
775
#endif  // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
776
  }
777
0
778
0
  int fd = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
779
0
  mLaunchOptions->fds_to_remap.push_back(
780
0
    std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
781
0
782
# ifdef MOZ_WIDGET_COCOA
783
  // Add a mach port to the command line so the child can communicate its
784
  // 'task_t' back to the parent.
785
  //
786
  // Put a random number into the channel name, so that a compromised renderer
787
  // can't pretend being the child that's forked off.
788
  std::string mach_connection_name = StringPrintf("org.mozilla.machname.%d",
789
                                                  base::RandInt(0, std::numeric_limits<int>::max()));
790
  childArgv.push_back(mach_connection_name.c_str());
791
# endif // MOZ_WIDGET_COCOA
792
793
0
  childArgv.push_back(childProcessType);
794
0
795
# ifdef MOZ_WIDGET_COCOA
796
  // Register the listening port before launching the child, to ensure
797
  // that it's there when the child tries to look it up.
798
  ReceivePort parent_recv_port(mach_connection_name.c_str());
799
# endif // MOZ_WIDGET_COCOA
800
801
# if defined(MOZ_WIDGET_ANDROID)
802
  LaunchAndroidService(childProcessType, childArgv,
803
                       mLaunchOptions->fds_to_remap, &process);
804
# else // goes with defined(MOZ_WIDGET_ANDROID)
805
  base::LaunchApp(childArgv, *mLaunchOptions, &process);
806
0
# endif // defined(MOZ_WIDGET_ANDROID)
807
0
808
0
  // We're in the parent and the child was launched. Close the child FD in the
809
0
  // parent as soon as possible, which will allow the parent to detect when the
810
0
  // child closes its FD (either due to normal exit or due to crash).
811
0
  GetChannel()->CloseClientFileDescriptor();
812
0
813
# ifdef MOZ_WIDGET_COCOA
814
  // Wait for the child process to send us its 'task_t' data.
815
  const int kTimeoutMs = 10000;
816
817
  MachReceiveMessage child_message;
818
  kern_return_t err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
819
  if (err != KERN_SUCCESS) {
820
    std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
821
    CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
822
    return false;
823
  }
824
825
  task_t child_task = child_message.GetTranslatedPort(0);
826
  if (child_task == MACH_PORT_NULL) {
827
    CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
828
    return false;
829
  }
830
831
  if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
832
    CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
833
    return false;
834
  }
835
  MachPortSender parent_sender(child_message.GetTranslatedPort(1));
836
837
  if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
838
    CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
839
  }
840
  auto* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2));
841
842
  if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
843
    CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
844
  }
845
  auto* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3));
846
847
  MachSendMessage parent_message(/* id= */0);
848
  if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
849
    CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
850
    return false;
851
  }
852
853
  auto* parent_recv_port_memory = new ReceivePort();
854
  if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
855
    CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed.";
856
    return false;
857
  }
858
859
  auto* parent_send_port_memory_ack = new ReceivePort();
860
  if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
861
    CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed.";
862
    return false;
863
  }
864
865
  err = parent_sender.SendMessage(parent_message, kTimeoutMs);
866
  if (err != KERN_SUCCESS) {
867
    std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
868
    CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
869
    return false;
870
  }
871
872
  SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack,
873
                                     parent_send_port_memory, parent_send_port_memory_ack, false);
874
875
# endif // MOZ_WIDGET_COCOA
876
877
0
//--------------------------------------------------
878
#elif defined(OS_WIN) // defined(OS_POSIX)
879
880
  FilePath exePath;
881
  BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
882
883
  CommandLine cmdLine(exePath.ToWStringHack());
884
885
  if (pathType == BinaryPathType::Self) {
886
    cmdLine.AppendLooseValue(UTF8ToWide("-contentproc"));
887
  }
888
889
  cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
890
891
  for (std::vector<std::string>::iterator it = aExtraOpts.begin();
892
       it != aExtraOpts.end();
893
       ++it) {
894
      cmdLine.AppendLooseValue(UTF8ToWide(*it));
895
  }
896
897
  if (Omnijar::IsInitialized()) {
898
    // Make sure the child process can find the omnijar
899
    // See XRE_InitCommandLine in nsAppRunner.cpp
900
    nsAutoString path;
901
    nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
902
    if (file && NS_SUCCEEDED(file->GetPath(path))) {
903
      cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
904
      cmdLine.AppendLooseValue(path.get());
905
    }
906
    file = Omnijar::GetPath(Omnijar::APP);
907
    if (file && NS_SUCCEEDED(file->GetPath(path))) {
908
      cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
909
      cmdLine.AppendLooseValue(path.get());
910
    }
911
  }
912
913
# if defined(MOZ_SANDBOX)
914
  bool shouldSandboxCurrentProcess = false;
915
916
  // XXX: Bug 1124167: We should get rid of the process specific logic for
917
  // sandboxing in this class at some point. Unfortunately it will take a bit
918
  // of reorganizing so I don't think this patch is the right time.
919
  switch (mProcessType) {
920
    case GeckoProcessType_Content:
921
#  if defined(MOZ_CONTENT_SANDBOX)
922
      if (mSandboxLevel > 0) {
923
        // For now we treat every failure as fatal in SetSecurityLevelForContentProcess
924
        // and just crash there right away. Should this change in the future then we
925
        // should also handle the error here.
926
        mSandboxBroker.SetSecurityLevelForContentProcess(mSandboxLevel,
927
                                                         mIsFileContent);
928
        shouldSandboxCurrentProcess = true;
929
      }
930
#  endif // defined(MOZ_CONTENT_SANDBOX)
931
      break;
932
    case GeckoProcessType_Plugin:
933
      if (mSandboxLevel > 0 &&
934
          !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
935
        bool ok = mSandboxBroker.SetSecurityLevelForPluginProcess(mSandboxLevel);
936
        if (!ok) {
937
          return false;
938
        }
939
        shouldSandboxCurrentProcess = true;
940
      }
941
      break;
942
#ifdef MOZ_ENABLE_SKIA_PDF
943
    case GeckoProcessType_PDFium:
944
      if (!PR_GetEnv("MOZ_DISABLE_PDFIUM_SANDBOX")) {
945
        bool ok = mSandboxBroker.SetSecurityLevelForPDFiumProcess();
946
        if (!ok) {
947
          return false;
948
        }
949
        shouldSandboxCurrentProcess = true;
950
      }
951
      break;
952
#endif
953
    case GeckoProcessType_IPDLUnitTest:
954
      // XXX: We don't sandbox this process type yet
955
      break;
956
    case GeckoProcessType_GMPlugin:
957
      if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
958
        // The Widevine CDM on Windows can only load at USER_RESTRICTED,
959
        // not at USER_LOCKDOWN. So look in the command line arguments
960
        // to see if we're loading the path to the Widevine CDM, and if
961
        // so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
962
        bool isWidevine = std::any_of(aExtraOpts.begin(), aExtraOpts.end(),
963
          [](const std::string arg) { return arg.find("gmp-widevinecdm") != std::string::npos; });
964
        auto level = isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
965
        bool ok = mSandboxBroker.SetSecurityLevelForGMPlugin(level);
966
        if (!ok) {
967
          return false;
968
        }
969
        shouldSandboxCurrentProcess = true;
970
      }
971
      break;
972
    case GeckoProcessType_GPU:
973
      if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_GPU_SANDBOX")) {
974
        // For now we treat every failure as fatal in SetSecurityLevelForGPUProcess
975
        // and just crash there right away. Should this change in the future then we
976
        // should also handle the error here.
977
        mSandboxBroker.SetSecurityLevelForGPUProcess(mSandboxLevel);
978
        shouldSandboxCurrentProcess = true;
979
      }
980
      break;
981
    case GeckoProcessType_VR:
982
      if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_VR_SANDBOX")) {
983
        // TODO: Implement sandbox for VR process, Bug 1430043.
984
      }
985
      break;
986
    case GeckoProcessType_Default:
987
    default:
988
      MOZ_CRASH("Bad process type in GeckoChildProcessHost");
989
      break;
990
  };
991
992
  if (shouldSandboxCurrentProcess) {
993
    for (auto it = mAllowedFilesRead.begin();
994
         it != mAllowedFilesRead.end();
995
         ++it) {
996
      mSandboxBroker.AllowReadFile(it->c_str());
997
    }
998
  }
999
# endif // defined(MOZ_SANDBOX)
1000
1001
  // Add the application directory path (-appdir path)
1002
  AddAppDirToCommandLine(cmdLine);
1003
1004
  // XXX Command line params past this point are expected to be at
1005
  // the end of the command line string, and in a specific order.
1006
  // See XRE_InitChildProcess in nsEmbedFunction.
1007
1008
  // Win app model id
1009
  cmdLine.AppendLooseValue(mGroupId.get());
1010
1011
  // Tmp dir that the GPU process should use for crash reports. This arg is
1012
  // always populated (but possibly with an empty value) for a GPU child process.
1013
  if (mProcessType == GeckoProcessType_GPU) {
1014
    nsCOMPtr<nsIFile> file;
1015
    CrashReporter::GetChildProcessTmpDir(getter_AddRefs(file));
1016
    nsString path;
1017
    if (file) {
1018
      MOZ_ALWAYS_SUCCEEDS(file->GetPath(path));
1019
    }
1020
    std::wstring wpath(path.get());
1021
    cmdLine.AppendLooseValue(wpath);
1022
  }
1023
1024
  // Process id
1025
  cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
1026
1027
  cmdLine.AppendLooseValue(
1028
    UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
1029
1030
  if (!CrashReporter::IsDummy()) {
1031
    PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
1032
    mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
1033
    std::string hStr = std::to_string(h);
1034
    cmdLine.AppendLooseValue(UTF8ToWide(hStr));
1035
  }
1036
1037
  // Process type
1038
  cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
1039
1040
# if defined(MOZ_SANDBOX)
1041
  if (shouldSandboxCurrentProcess) {
1042
    // Mark the handles to inherit as inheritable.
1043
    for (HANDLE h : mLaunchOptions->handles_to_inherit) {
1044
      mSandboxBroker.AddHandleToShare(h);
1045
    }
1046
1047
    if (mSandboxBroker.LaunchApp(cmdLine.program().c_str(),
1048
                                 cmdLine.command_line_string().c_str(),
1049
                                 mLaunchOptions->env_map,
1050
                                 mProcessType,
1051
                                 mEnableSandboxLogging,
1052
                                 &process)) {
1053
      EnvironmentLog("MOZ_PROCESS_LOG").print(
1054
        "==> process %d launched child process %d (%S)\n",
1055
        base::GetCurrentProcId(), base::GetProcId(process),
1056
        cmdLine.command_line_string().c_str());
1057
    }
1058
  } else
1059
# endif // defined(MOZ_SANDBOX)
1060
  {
1061
    base::LaunchApp(cmdLine, *mLaunchOptions, &process);
1062
1063
# ifdef MOZ_SANDBOX
1064
    // We need to be able to duplicate handles to some types of non-sandboxed
1065
    // child processes.
1066
    if (mProcessType == GeckoProcessType_Content ||
1067
        mProcessType == GeckoProcessType_GPU ||
1068
        mProcessType == GeckoProcessType_VR ||
1069
        mProcessType == GeckoProcessType_GMPlugin) {
1070
      if (!mSandboxBroker.AddTargetPeer(process)) {
1071
        NS_WARNING("Failed to add content process as target peer.");
1072
      }
1073
    }
1074
# endif // MOZ_SANDBOX
1075
  }
1076
1077
#else // goes with defined(OS_POSIX)
1078
#  error Sorry
1079
#endif // defined(OS_POSIX)
1080
1081
0
  if (!process) {
1082
0
    return false;
1083
0
  }
1084
0
  // NB: on OS X, we block much longer than we need to in order to
1085
0
  // reach this call, waiting for the child process's task_t.  The
1086
0
  // best way to fix that is to refactor this file, hard.
1087
#if defined(MOZ_WIDGET_COCOA)
1088
  mChildTask = child_task;
1089
#endif // defined(MOZ_WIDGET_COCOA)
1090
1091
0
  if (!OpenPrivilegedHandle(base::GetProcId(process))
1092
#ifdef XP_WIN
1093
      // If we failed in opening the process handle, try harder by duplicating
1094
      // one.
1095
      && !::DuplicateHandle(::GetCurrentProcess(), process,
1096
                            ::GetCurrentProcess(), &mChildProcessHandle,
1097
                            PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
1098
                            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
1099
                            SYNCHRONIZE,
1100
                            FALSE, 0)
1101
#endif // XP_WIN
1102
0
     ) {
1103
0
    MOZ_CRASH("cannot open handle to child process");
1104
0
  }
1105
#if defined(XP_WIN)
1106
  CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
1107
    base::GetProcId(process), crashAnnotationReadPipe);
1108
#else
1109
0
  CrashReporter::RegisterChildCrashAnnotationFileDescriptor(process,
1110
0
                                                            crashAnnotationReadPipe);
1111
0
#endif
1112
0
  PR_Close(crashAnnotationWritePipe);
1113
0
1114
0
  MonitorAutoLock lock(mMonitor);
1115
0
  mProcessState = PROCESS_CREATED;
1116
0
  lock.Notify();
1117
0
1118
0
  mLaunchOptions = nullptr;
1119
0
  return true;
1120
0
}
1121
1122
bool
1123
GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
1124
0
{
1125
0
  if (mChildProcessHandle) {
1126
0
    MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
1127
0
    return true;
1128
0
  }
1129
0
1130
0
  return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
1131
0
}
1132
1133
void
1134
GeckoChildProcessHost::OnProcessHandleReady(ProcessHandle aProcessHandle)
1135
0
{}
1136
1137
void
1138
GeckoChildProcessHost::OnProcessLaunchError()
1139
0
{}
1140
1141
void
1142
GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
1143
0
{
1144
0
  if (!OpenPrivilegedHandle(peer_pid)) {
1145
0
    MOZ_CRASH("can't open handle to child process");
1146
0
  }
1147
0
  MonitorAutoLock lock(mMonitor);
1148
0
  mProcessState = PROCESS_CONNECTED;
1149
0
  lock.Notify();
1150
0
}
1151
1152
void
1153
GeckoChildProcessHost::OnMessageReceived(IPC::Message&& aMsg)
1154
0
{
1155
0
  // We never process messages ourself, just save them up for the next
1156
0
  // listener.
1157
0
  mQueue.push(std::move(aMsg));
1158
0
}
1159
1160
void
1161
GeckoChildProcessHost::OnChannelError()
1162
0
{
1163
0
  // Update the process state to an error state if we have a channel
1164
0
  // error before we're connected. This fixes certain failures,
1165
0
  // but does not address the full range of possible issues described
1166
0
  // in the FIXME comment below.
1167
0
  MonitorAutoLock lock(mMonitor);
1168
0
  if (mProcessState < PROCESS_CONNECTED) {
1169
0
    mProcessState = PROCESS_ERROR;
1170
0
    lock.Notify();
1171
0
  }
1172
0
  // FIXME/bug 773925: save up this error for the next listener.
1173
0
}
1174
1175
void
1176
GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue)
1177
0
{
1178
0
  // If this is called off the IO thread, bad things will happen.
1179
0
  DCHECK(MessageLoopForIO::current());
1180
0
  swap(queue, mQueue);
1181
0
  // We expect the next listener to take over processing of our queue.
1182
0
}
1183
1184
bool GeckoChildProcessHost::sRunSelfAsContentProc(false);
1185
1186
#ifdef MOZ_WIDGET_ANDROID
1187
void
1188
GeckoChildProcessHost::LaunchAndroidService(const char* type,
1189
                                            const std::vector<std::string>& argv,
1190
                                            const base::file_handle_mapping_vector& fds_to_remap,
1191
                                            ProcessHandle* process_handle)
1192
{
1193
  MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 5));
1194
  JNIEnv* const env = mozilla::jni::GetEnvForThread();
1195
  MOZ_ASSERT(env);
1196
1197
  const int argvSize = argv.size();
1198
  jni::ObjectArray::LocalRef jargs = jni::ObjectArray::New<jni::String>(argvSize);
1199
  for (int ix = 0; ix < argvSize; ix++) {
1200
    jargs->SetElement(ix, jni::StringParam(argv[ix].c_str(), env));
1201
  }
1202
1203
  // XXX: this processing depends entirely on the internals of
1204
  // ContentParent::LaunchSubprocess()
1205
  // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
1206
  // which they append to fds_to_remap. There must be a better way to do it.
1207
  // See bug 1440207.
1208
  int32_t prefsFd = fds_to_remap[0].first;
1209
  int32_t prefMapFd = fds_to_remap[1].first;
1210
  int32_t ipcFd = fds_to_remap[2].first;
1211
  int32_t crashFd = -1;
1212
  int32_t crashAnnotationFd = -1;
1213
  if (fds_to_remap.size() == 4) {
1214
    crashAnnotationFd = fds_to_remap[3].first;
1215
  }
1216
  if (fds_to_remap.size() == 5) {
1217
    crashFd = fds_to_remap[3].first;
1218
    crashAnnotationFd = fds_to_remap[4].first;
1219
  }
1220
1221
  int32_t handle = java::GeckoProcessManager::Start(type, jargs, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd);
1222
1223
  if (process_handle) {
1224
    *process_handle = handle;
1225
  }
1226
}
1227
#endif