SandboxTestingChild.cpp (5609B)
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 https://mozilla.org/MPL/2.0/. */ 6 7 #include "SandboxTestingChild.h" 8 #include "SandboxTestingChildTests.h" 9 #include "SandboxTestingThread.h" 10 #include "mozilla/ipc/Endpoint.h" 11 #include "mozilla/ipc/UtilityProcessSandboxing.h" 12 #include "mozilla/ipc/UtilityProcessChild.h" 13 14 #ifdef XP_LINUX 15 # include "mozilla/Sandbox.h" 16 #endif 17 18 #include "nsXULAppAPI.h" 19 20 namespace mozilla { 21 22 StaticRefPtr<SandboxTestingChild> SandboxTestingChild::sInstance; 23 24 bool SandboxTestingChild::IsTestThread() { return mThread->IsOnThread(); } 25 26 void SandboxTestingChild::PostToTestThread( 27 already_AddRefed<nsIRunnable>&& runnable) { 28 mThread->Dispatch(std::move(runnable)); 29 } 30 31 /* static */ 32 bool SandboxTestingChild::Initialize( 33 Endpoint<PSandboxTestingChild>&& aSandboxTestingEndpoint) { 34 MOZ_ASSERT(!sInstance); 35 SandboxTestingThread* thread = SandboxTestingThread::Create(); 36 if (!thread) { 37 return false; 38 } 39 sInstance = 40 new SandboxTestingChild(thread, std::move(aSandboxTestingEndpoint)); 41 thread->Dispatch(NewRunnableMethod<Endpoint<PSandboxTestingChild>&&>( 42 "SandboxTestingChild::Bind", sInstance.get(), &SandboxTestingChild::Bind, 43 std::move(aSandboxTestingEndpoint))); 44 return true; 45 } 46 47 /* static */ 48 SandboxTestingChild* SandboxTestingChild::GetInstance() { 49 MOZ_ASSERT(sInstance, "Must initialize SandboxTestingChild before using it"); 50 return sInstance; 51 } 52 53 SandboxTestingChild::SandboxTestingChild( 54 SandboxTestingThread* aThread, Endpoint<PSandboxTestingChild>&& aEndpoint) 55 : mThread(aThread) {} 56 57 SandboxTestingChild::~SandboxTestingChild() = default; 58 59 void SandboxTestingChild::Bind(Endpoint<PSandboxTestingChild>&& aEndpoint) { 60 MOZ_RELEASE_ASSERT(mThread->IsOnThread()); 61 DebugOnly<bool> ok = aEndpoint.Bind(this); 62 MOZ_ASSERT(ok); 63 64 #ifdef XP_LINUX 65 bool sandboxCrashOnError = SetSandboxCrashOnError(false); 66 #endif 67 68 if (XRE_IsContentProcess()) { 69 RunTestsContent(this); 70 } 71 72 if (XRE_IsRDDProcess()) { 73 RunTestsRDD(this); 74 } 75 76 if (XRE_IsGMPluginProcess()) { 77 RunTestsGMPlugin(this); 78 } 79 80 if (XRE_IsSocketProcess()) { 81 RunTestsSocket(this); 82 } 83 84 if (XRE_IsGPUProcess()) { 85 RunTestsGPU(this); 86 } 87 88 if (XRE_IsUtilityProcess()) { 89 RefPtr<ipc::UtilityProcessChild> s = ipc::UtilityProcessChild::Get(); 90 MOZ_ASSERT(s, "Unable to grab a UtilityProcessChild"); 91 switch (s->mSandbox) { 92 case ipc::SandboxingKind::GENERIC_UTILITY: 93 RunTestsGenericUtility(this); 94 RunTestsUtilityMediaService(this, s->mSandbox); 95 break; 96 #ifdef MOZ_APPLEMEDIA 97 case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA: 98 RunTestsUtilityMediaService(this, s->mSandbox); 99 break; 100 #endif 101 #ifdef XP_WIN 102 case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_WMF: 103 RunTestsUtilityMediaService(this, s->mSandbox); 104 break; 105 #endif 106 107 default: 108 MOZ_ASSERT(false, "Invalid SandboxingKind"); 109 break; 110 } 111 } 112 113 #ifdef XP_LINUX 114 SetSandboxCrashOnError(sandboxCrashOnError); 115 #endif 116 117 // Tell SandboxTest that this process is done with all tests. 118 SendTestCompleted(); 119 } 120 121 void SandboxTestingChild::ActorDestroy(ActorDestroyReason aWhy) { 122 MOZ_ASSERT(mThread->IsOnThread()); 123 NS_DispatchToMainThread(NS_NewRunnableFunction( 124 "SandboxChildDestroyer", []() { SandboxTestingChild::Destroy(); })); 125 } 126 127 void SandboxTestingChild::Destroy() { 128 MOZ_ASSERT(NS_IsMainThread()); 129 MOZ_ASSERT(sInstance); 130 sInstance = nullptr; 131 } 132 133 ipc::IPCResult SandboxTestingChild::RecvShutDown() { 134 Close(); 135 return IPC_OK(); 136 } 137 138 void SandboxTestingChild::ReportNoTests() { 139 SendReportTestResults("dummy_test"_ns, /* passed */ true, 140 "The test framework fails if there are no cases."_ns); 141 } 142 143 template <typename F> 144 void SandboxTestingChild::ErrnoTest(const nsCString& aName, bool aExpectSuccess, 145 F&& aFunction) { 146 int status = aFunction() >= 0 ? 0 : errno; 147 PosixTest(aName, aExpectSuccess, status); 148 } 149 150 template <typename F> 151 void SandboxTestingChild::ErrnoValueTest(const nsCString& aName, 152 int aExpectedErrno, F&& aFunction) { 153 int status = aFunction() >= 0 ? 0 : errno; 154 PosixTest(aName, aExpectedErrno == 0, status, Some(aExpectedErrno)); 155 } 156 157 void SandboxTestingChild::PosixTest(const nsCString& aName, bool aExpectSuccess, 158 int aStatus, Maybe<int> aExpectedError) { 159 nsAutoCString message; 160 bool passed; 161 162 // The "expected" arguments are a little redundant. 163 MOZ_ASSERT(!aExpectedError || aExpectSuccess == (*aExpectedError == 0)); 164 165 // Decide whether the test passed, and stringify the actual result. 166 if (aStatus == 0) { 167 message = "Succeeded"_ns; 168 passed = aExpectSuccess; 169 } else { 170 message = "Error: "_ns; 171 message += strerror(aStatus); 172 if (aExpectedError) { 173 passed = aStatus == *aExpectedError; 174 } else { 175 passed = !aExpectSuccess; 176 } 177 } 178 179 // If something unexpected happened, mention the expected result. 180 if (!passed) { 181 message += "; expected "; 182 if (aExpectSuccess) { 183 message += "success"; 184 } else { 185 message += "error"; 186 if (aExpectedError) { 187 message += ": "; 188 message += strerror(*aExpectedError); 189 } 190 } 191 } 192 193 SendReportTestResults(aName, passed, message); 194 } 195 196 } // namespace mozilla