diff options
Diffstat (limited to 'security/sandbox/common/test/SandboxTestingChild.cpp')
-rw-r--r-- | security/sandbox/common/test/SandboxTestingChild.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/security/sandbox/common/test/SandboxTestingChild.cpp b/security/sandbox/common/test/SandboxTestingChild.cpp new file mode 100644 index 0000000000..3a9d61556c --- /dev/null +++ b/security/sandbox/common/test/SandboxTestingChild.cpp @@ -0,0 +1,194 @@ +/* -*- 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 "SandboxTestingChild.h" +#include "SandboxTestingChildTests.h" +#include "SandboxTestingThread.h" +#include "mozilla/ipc/Endpoint.h" +#include "mozilla/ipc/UtilityProcessSandboxing.h" +#include "mozilla/ipc/UtilityProcessChild.h" + +#ifdef XP_LINUX +# include "mozilla/Sandbox.h" +#endif + +#include "nsXULAppAPI.h" + +namespace mozilla { + +StaticRefPtr<SandboxTestingChild> SandboxTestingChild::sInstance; + +bool SandboxTestingChild::IsTestThread() { return mThread->IsOnThread(); } + +void SandboxTestingChild::PostToTestThread( + already_AddRefed<nsIRunnable>&& runnable) { + mThread->Dispatch(std::move(runnable)); +} + +/* static */ +bool SandboxTestingChild::Initialize( + Endpoint<PSandboxTestingChild>&& aSandboxTestingEndpoint) { + MOZ_ASSERT(!sInstance); + SandboxTestingThread* thread = SandboxTestingThread::Create(); + if (!thread) { + return false; + } + sInstance = + new SandboxTestingChild(thread, std::move(aSandboxTestingEndpoint)); + thread->Dispatch(NewRunnableMethod<Endpoint<PSandboxTestingChild>&&>( + "SandboxTestingChild::Bind", sInstance.get(), &SandboxTestingChild::Bind, + std::move(aSandboxTestingEndpoint))); + return true; +} + +/* static */ +SandboxTestingChild* SandboxTestingChild::GetInstance() { + MOZ_ASSERT(sInstance, "Must initialize SandboxTestingChild before using it"); + return sInstance; +} + +SandboxTestingChild::SandboxTestingChild( + SandboxTestingThread* aThread, Endpoint<PSandboxTestingChild>&& aEndpoint) + : mThread(aThread) {} + +SandboxTestingChild::~SandboxTestingChild() = default; + +void SandboxTestingChild::Bind(Endpoint<PSandboxTestingChild>&& aEndpoint) { + MOZ_RELEASE_ASSERT(mThread->IsOnThread()); + DebugOnly<bool> ok = aEndpoint.Bind(this); + MOZ_ASSERT(ok); + +#ifdef XP_LINUX + bool sandboxCrashOnError = SetSandboxCrashOnError(false); +#endif + + if (XRE_IsContentProcess()) { + RunTestsContent(this); + } + + if (XRE_IsRDDProcess()) { + RunTestsRDD(this); + } + + if (XRE_IsGMPluginProcess()) { + RunTestsGMPlugin(this); + } + + if (XRE_IsSocketProcess()) { + RunTestsSocket(this); + } + + if (XRE_IsGPUProcess()) { + RunTestsGPU(this); + } + + if (XRE_IsUtilityProcess()) { + RefPtr<ipc::UtilityProcessChild> s = ipc::UtilityProcessChild::Get(); + MOZ_ASSERT(s, "Unable to grab a UtilityProcessChild"); + switch (s->mSandbox) { + case ipc::SandboxingKind::GENERIC_UTILITY: + RunTestsGenericUtility(this); +#ifdef MOZ_APPLEMEDIA + [[fallthrough]]; + case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA: +#endif +#ifdef XP_WIN + [[fallthrough]]; + case ipc::SandboxingKind::UTILITY_AUDIO_DECODING_WMF: +#endif + RunTestsUtilityAudioDecoder(this, s->mSandbox); + break; + + default: + MOZ_ASSERT(false, "Invalid SandboxingKind"); + break; + } + } + +#ifdef XP_LINUX + SetSandboxCrashOnError(sandboxCrashOnError); +#endif + + // Tell SandboxTest that this process is done with all tests. + SendTestCompleted(); +} + +void SandboxTestingChild::ActorDestroy(ActorDestroyReason aWhy) { + MOZ_ASSERT(mThread->IsOnThread()); + NS_DispatchToMainThread(NS_NewRunnableFunction( + "SandboxChildDestroyer", []() { SandboxTestingChild::Destroy(); })); +} + +void SandboxTestingChild::Destroy() { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(sInstance); + sInstance = nullptr; +} + +ipc::IPCResult SandboxTestingChild::RecvShutDown() { + Close(); + return IPC_OK(); +} + +void SandboxTestingChild::ReportNoTests() { + SendReportTestResults("dummy_test"_ns, /* passed */ true, + "The test framework fails if there are no cases."_ns); +} + +template <typename F> +void SandboxTestingChild::ErrnoTest(const nsCString& aName, bool aExpectSuccess, + F&& aFunction) { + int status = aFunction() >= 0 ? 0 : errno; + PosixTest(aName, aExpectSuccess, status); +} + +template <typename F> +void SandboxTestingChild::ErrnoValueTest(const nsCString& aName, + int aExpectedErrno, F&& aFunction) { + int status = aFunction() >= 0 ? 0 : errno; + PosixTest(aName, aExpectedErrno == 0, status, Some(aExpectedErrno)); +} + +void SandboxTestingChild::PosixTest(const nsCString& aName, bool aExpectSuccess, + int aStatus, Maybe<int> aExpectedError) { + nsAutoCString message; + bool passed; + + // The "expected" arguments are a little redundant. + MOZ_ASSERT(!aExpectedError || aExpectSuccess == (*aExpectedError == 0)); + + // Decide whether the test passed, and stringify the actual result. + if (aStatus == 0) { + message = "Succeeded"_ns; + passed = aExpectSuccess; + } else { + message = "Error: "_ns; + message += strerror(aStatus); + if (aExpectedError) { + passed = aStatus == *aExpectedError; + } else { + passed = !aExpectSuccess; + } + } + + // If something unexpected happened, mention the expected result. + if (!passed) { + message += "; expected "; + if (aExpectSuccess) { + message += "success"; + } else { + message += "error"; + if (aExpectedError) { + message += ": "; + message += strerror(*aExpectedError); + } + } + } + + SendReportTestResults(aName, passed, message); +} + +} // namespace mozilla |