summaryrefslogtreecommitdiffstats
path: root/security/sandbox/win/src/remotesandboxbroker/remoteSandboxBroker.cpp
blob: d1148e985a282d24b9999b4e60bb69555211dbd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "remoteSandboxBroker.h"

#include "RemoteSandboxBrokerParent.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsIThread.h"

namespace mozilla {

RemoteSandboxBroker::RemoteSandboxBroker(uint32_t aLaunchArch)
    : mParent(new RemoteSandboxBrokerParent), mLaunchArch(aLaunchArch) {}

RemoteSandboxBroker::~RemoteSandboxBroker() {
  MOZ_ASSERT(
      mShutdown,
      "Shutdown must be called on RemoteSandboxBroker before destruction!");
}

void RemoteSandboxBroker::Shutdown() {
  MOZ_ASSERT(!mShutdown, "Don't call Shutdown() twice!");
  mShutdown = true;

  if (!mIPCLaunchThread) {
    // Can't have launched child process, nothing to shutdown.
    return;
  }

  RefPtr<RemoteSandboxBroker> self = this;
  mIPCLaunchThread->Dispatch(
      NS_NewRunnableFunction("Remote Sandbox Launch", [self, this]() {
        // Note: `self` here should be the last reference to this instance.
        mParent->Shutdown();
        mIPCLaunchThread = nullptr;
      }));
}

Result<Ok, mozilla::ipc::LaunchError> RemoteSandboxBroker::LaunchApp(
    const wchar_t* aPath, const wchar_t* aArguments,
    base::EnvironmentMap& aEnvironment, GeckoProcessType aProcessType,
    const bool aEnableLogging, const IMAGE_THUNK_DATA*, void** aProcessHandle) {
  // Note: we expect to be called on the IPC launch thread from
  // GeckoChildProcesHost while it's launching a child process. The IPC launch
  // thread is a TaskQueue. We can't run a synchronous launch here as that
  // blocks the calling thread while it dispatches a task to the IPC launch
  // thread to spawn the process. Since our calling thread is the IPC launch
  // thread, we'd then be deadlocked. So instead we do an async launch, and spin
  // the event loop until the process launch succeeds.

  // We should be on the IPC launch thread. We're shutdown on the IO thread,
  // so save a ref to the IPC launch thread here, so we can close the channel
  // on the IPC launch thread on shutdown.
  mIPCLaunchThread = GetCurrentSerialEventTarget();

  mParameters.path() = nsDependentString(aPath);
  mParameters.args() = nsDependentString(aArguments);

  auto toNsString = [](const std::wstring& s) {
    return nsDependentString(s.c_str());
  };
  for (auto itr : aEnvironment) {
    mParameters.env().AppendElement(
        EnvVar(toNsString(itr.first), toNsString(itr.second)));
  }

  mParameters.processType() = uint32_t(aProcessType);
  mParameters.enableLogging() = aEnableLogging;

  enum Result { Pending, Succeeded, Failed };
  Result res = Pending;
  auto resolve = [&](bool ok) {
    res = Succeeded;
    return GenericPromise::CreateAndResolve(ok, __func__);
  };

  auto reject = [&](nsresult) {
    res = Failed;
    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
  };

  // We need to wait on the current thread for the process to launch which will
  // block the running IPC Launch taskqueue. We cannot use
  // GetCurrentSerialEventTarget() (as this returns the currently running
  // TaskQueue) to resolve our promise as it will be blocked until we return
  // from this function.
  nsCOMPtr<nsISerialEventTarget> target = NS_GetCurrentThread();
  mParent->Launch(mLaunchArch, mParameters.shareHandles(), target)
      ->Then(target, __func__, std::move(resolve), std::move(reject));

  // Spin the event loop while the sandbox launcher process launches.
  SpinEventLoopUntil("RemoteSandboxBroker::LaunchApp"_ns,
                     [&]() { return res != Pending; });

  if (res == Failed) {
    return Err(mozilla::ipc::LaunchError("RSB::LaunchApp"));
  }

  uint64_t handle = 0;
  bool ok = false;
  bool rv = mParent->SendLaunchApp(std::move(mParameters), &ok, &handle) && ok;
  mParameters.shareHandles().Clear();
  if (!rv) {
    mParent->Shutdown();
    return Err(mozilla::ipc::LaunchError("RSB::SendLaunchApp"));
  }

  // Duplicate the handle of the child process that the launcher launched from
  // the launcher process's space into this process' space.
  HANDLE ourChildHandle = 0;
  bool dh = mParent->DuplicateFromLauncher((HANDLE)handle, &ourChildHandle);
  if (!dh) {
    mParent->Shutdown();
    return Err(mozilla::ipc::LaunchError("RSB::DuplicateFromLauncher"));
  }

  *aProcessHandle = (void**)(ourChildHandle);

  base::ProcessHandle process = *aProcessHandle;
  SandboxBroker::AddTargetPeer(process);

  return Ok();
}

bool RemoteSandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
                                                      bool aIsRemoteLaunch) {
  mParameters.sandboxLevel() = uint32_t(aLevel);
  return true;
}

bool RemoteSandboxBroker::AllowReadFile(wchar_t const* aFile) {
  mParameters.allowedReadFiles().AppendElement(nsDependentString(aFile));
  return true;
}

void RemoteSandboxBroker::AddHandleToShare(HANDLE aHandle) {
  mParameters.shareHandles().AppendElement(uint64_t(aHandle));
}

void RemoteSandboxBroker::SetSecurityLevelForContentProcess(
    int32_t aSandboxLevel, bool aIsFileProcess) {
  MOZ_CRASH(
      "RemoteSandboxBroker::SetSecurityLevelForContentProcess not Implemented");
}

void RemoteSandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) {
  MOZ_CRASH(
      "RemoteSandboxBroker::SetSecurityLevelForGPUProcess not Implemented");
}

bool RemoteSandboxBroker::SetSecurityLevelForRDDProcess() {
  MOZ_CRASH(
      "RemoteSandboxBroker::SetSecurityLevelForRDDProcess not Implemented");
}

bool RemoteSandboxBroker::SetSecurityLevelForSocketProcess() {
  MOZ_CRASH(
      "RemoteSandboxBroker::SetSecurityLevelForSocketProcess not Implemented");
}

bool RemoteSandboxBroker::SetSecurityLevelForUtilityProcess(
    mozilla::ipc::SandboxingKind aSandbox) {
  MOZ_CRASH(
      "RemoteSandboxBroker::SetSecurityLevelForUtilityProcess not Implemented");
}

}  // namespace mozilla