diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index aadd8184c70e..aac991d06bd2 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -21,6 +21,10 @@ include protocol PProxyConfigLookup; include protocol PNativeDNSResolverOverride; include protocol PRemoteLazyInputStream; +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) +include protocol PSandboxTesting; +#endif + include MemoryReportTypes; include NeckoChannelParams; include PrefsTypes; @@ -143,6 +147,9 @@ child: async InitLinuxSandbox(FileDescriptor? sandboxBroker); async InitSocketProcessBridgeParent(ProcessId processId, Endpoint endpoint); async InitProfiler(Endpoint aEndpoint); +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) + async InitSandboxTesting(Endpoint aEndpoint); +#endif // test-only async SocketProcessTelemetryPing(); diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index d1396ef0f99a..eb6485591dc4 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -61,6 +61,10 @@ # include "mozilla/net/WebrtcTCPSocketChild.h" #endif +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) +# include "mozilla/SandboxTestingChild.h" +#endif + namespace mozilla { namespace net { @@ -275,6 +279,17 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvInitProfiler( return IPC_OK(); } +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) +mozilla::ipc::IPCResult SocketProcessChild::RecvInitSandboxTesting( + Endpoint&& aEndpoint) { + if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) { + return IPC_FAIL( + this, "InitSandboxTesting failed to initialise the child process."); + } + return IPC_OK(); +} +#endif + mozilla::ipc::IPCResult SocketProcessChild::RecvSocketProcessTelemetryPing() { const uint32_t kExpectedUintValue = 42; Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_SOCKET_ONLY_UINT, diff --git a/netwerk/ipc/SocketProcessChild.h b/netwerk/ipc/SocketProcessChild.h index de3f85320fef..900577aa5b91 100644 --- a/netwerk/ipc/SocketProcessChild.h +++ b/netwerk/ipc/SocketProcessChild.h @@ -56,6 +56,10 @@ class SocketProcessChild final Endpoint&& aEndpoint); mozilla::ipc::IPCResult RecvInitProfiler( Endpoint&& aEndpoint); +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) + mozilla::ipc::IPCResult RecvInitSandboxTesting( + Endpoint&& aEndpoint); +#endif mozilla::ipc::IPCResult RecvSocketProcessTelemetryPing(); PWebrtcTCPSocketChild* AllocPWebrtcTCPSocketChild(const Maybe& tabId); diff --git a/netwerk/ipc/moz.build b/netwerk/ipc/moz.build index f1642b06fae2..4462f2c0da87 100644 --- a/netwerk/ipc/moz.build +++ b/netwerk/ipc/moz.build @@ -56,6 +56,7 @@ UNIFIED_SOURCES += [ PREPROCESSED_IPDL_SOURCES += [ "PNecko.ipdl", + "PSocketProcess.ipdl", ] IPDL_SOURCES = [ @@ -66,7 +67,6 @@ IPDL_SOURCES = [ "PInputChannelThrottleQueue.ipdl", "PProxyConfigLookup.ipdl", "PSimpleChannel.ipdl", - "PSocketProcess.ipdl", "PSocketProcessBridge.ipdl", ] diff --git a/security/sandbox/common/moz.build b/security/sandbox/common/moz.build index 384fe245f72a..0116873a9ad0 100644 --- a/security/sandbox/common/moz.build +++ b/security/sandbox/common/moz.build @@ -41,6 +41,10 @@ if CONFIG["MOZ_SANDBOX"] and CONFIG["MOZ_DEBUG"] and CONFIG["ENABLE_TESTS"]: "test/mozISandboxTest.idl", ] + LOCAL_INCLUDES += [ + "/netwerk/base", + ] + include("/ipc/chromium/chromium-config.mozbuild") FINAL_LIBRARY = "xul" diff --git a/security/sandbox/common/test/SandboxTest.cpp b/security/sandbox/common/test/SandboxTest.cpp index c196da686b60..5353ed5f96b2 100644 --- a/security/sandbox/common/test/SandboxTest.cpp +++ b/security/sandbox/common/test/SandboxTest.cpp @@ -7,12 +7,15 @@ #include "SandboxTest.h" #include "mozilla/Components.h" +#include "mozilla/Preferences.h" #include "SandboxTestingParent.h" #include "SandboxTestingChild.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GPUChild.h" +#include "mozilla/net/SocketProcessParent.h" #include "mozilla/ipc/Endpoint.h" +#include "nsIOService.h" using namespace mozilla; using namespace mozilla::ipc; @@ -84,6 +87,40 @@ SandboxTest::StartTests(const nsTArray& aProcessesList) { break; } + case GeckoProcessType_Socket: { + // mochitest harness force this variable, but we actually do not want + // that + int rv_unset = +#ifdef XP_UNIX + unsetenv("MOZ_DISABLE_SOCKET_PROCESS"); +#endif // XP_UNIX +#ifdef XP_WIN + _putenv("MOZ_DISABLE_SOCKET_PROCESS="); +#endif // XP_WIN + MOZ_ASSERT(rv_unset == 0, "Error unsetting env var"); + + nsresult rv_pref = + Preferences::SetBool("network.process.enabled", true); + MOZ_ASSERT(rv_pref == NS_OK, "Error enforcing pref"); + + MOZ_ASSERT(net::gIOService, "No gIOService?"); + RefPtr self = this; + net::gIOService->CallOrWaitForSocketProcess([self, type]() { + // If socket process was previously disabled by env, + // nsIOService code will take some time before it creates the new + // process and it triggers this callback + // + // If that happens, then by the time we reach the end of StartTests() + // the mSandboxTestingParents[type] might not yet have been updated + // this is why below we allow for a delayed dispatch to give a chance + net::SocketProcessParent* parent = + net::SocketProcessParent::GetSingleton(); + self->mSandboxTestingParents[type] = + InitializeSandboxTestingActors(parent); + }); + break; + } + default: MOZ_ASSERT_UNREACHABLE( "SandboxTest does not yet support this process type"); @@ -91,7 +128,24 @@ SandboxTest::StartTests(const nsTArray& aProcessesList) { } if (!mSandboxTestingParents[type]) { - return NS_ERROR_FAILURE; + if (type == GeckoProcessType_Socket) { + // Give a chance to the socket process to be present and to the callback + // above to be ran. We delay by 5 seconds, but hopefully since it is all + // on the main thread, the value itself should not be important. + RefPtr self = this; + NS_DelayedDispatchToCurrentThread( + NS_NewRunnableFunction( + "SandboxTest::StartTests", + [self, type]() { + if (!self->mSandboxTestingParents[type]) { + MOZ_ASSERT_UNREACHABLE( + "SandboxTest failed to get a Parent"); + } + }), + 5e3 /* delay by five seconds */); + } else { + return NS_ERROR_FAILURE; + } } } return NS_OK; diff --git a/security/sandbox/common/test/SandboxTestingChild.cpp b/security/sandbox/common/test/SandboxTestingChild.cpp index be68b2ba4635..cd391882c4b2 100644 --- a/security/sandbox/common/test/SandboxTestingChild.cpp +++ b/security/sandbox/common/test/SandboxTestingChild.cpp @@ -5,18 +5,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "SandboxTestingChild.h" +#include "SandboxTestingChildTests.h" #include "SandboxTestingThread.h" -#include "nsXULAppAPI.h" - -#ifdef XP_UNIX -# include -# include -# include -# include -# include +#ifdef XP_LINUX +# include "mozilla/Sandbox.h" #endif +#include "nsXULAppAPI.h" + namespace mozilla { SandboxTestingChild* SandboxTestingChild::sInstance = nullptr; @@ -61,37 +58,22 @@ void SandboxTestingChild::Bind(Endpoint&& aEndpoint) { DebugOnly ok = aEndpoint.Bind(this); MOZ_ASSERT(ok); +#ifdef XP_LINUX + bool sandboxCrashOnError = SetSandboxCrashOnError(false); +#endif + if (XRE_IsContentProcess()) { -#ifdef XP_UNIX - struct stat st; - static const char kAllowedPath[] = "/usr/lib"; - - ErrnoTest("fstatat_as_stat"_ns, true, - [&] { return fstatat(AT_FDCWD, kAllowedPath, &st, 0); }); - ErrnoTest("fstatat_as_lstat"_ns, true, [&] { - return fstatat(AT_FDCWD, kAllowedPath, &st, AT_SYMLINK_NOFOLLOW); - }); - -# ifdef XP_LINUX - ErrnoTest("fstatat_as_fstat"_ns, true, - [&] { return fstatat(0, "", &st, AT_EMPTY_PATH); }); -# endif // XP_LINUX - - const struct timespec usec = {0, 1000}; - ErrnoTest("nanosleep"_ns, true, [&] { return nanosleep(&usec, nullptr); }); - - struct timespec res = {0, 0}; - ErrnoTest("clock_getres"_ns, true, - [&] { return clock_getres(CLOCK_REALTIME, &res); }); - -#else // XP_UNIX - SendReportTestResults("dummy_test"_ns, - /* shouldSucceed */ true, - /* didSucceed */ true, - "The test framework fails if there are no cases."_ns); -#endif // XP_UNIX + RunTestsContent(this); } + if (XRE_IsSocketProcess()) { + RunTestsSocket(this); + } + +#ifdef XP_LINUX + SetSandboxCrashOnError(sandboxCrashOnError); +#endif + // Tell SandboxTest that this process is done with all tests. SendTestCompleted(); } diff --git a/security/sandbox/common/test/SandboxTestingChild.h b/security/sandbox/common/test/SandboxTestingChild.h index 4ac3f577f54e..123b0dcb4736 100644 --- a/security/sandbox/common/test/SandboxTestingChild.h +++ b/security/sandbox/common/test/SandboxTestingChild.h @@ -40,11 +40,6 @@ class SandboxTestingChild : public PSandboxTestingChild { virtual bool RecvShutDown(); - private: - explicit SandboxTestingChild(SandboxTestingThread* aThread, - Endpoint&& aEndpoint); - void Bind(Endpoint&& aEndpoint); - #ifdef XP_UNIX // For test cases that return an error number or 0, like newer POSIX APIs. void PosixTest(const nsCString& aName, bool aExpectSuccess, int aStatus); @@ -56,6 +51,11 @@ class SandboxTestingChild : public PSandboxTestingChild { void ErrnoTest(const nsCString& aName, bool aExpectSuccess, F&& aFunction); #endif + private: + explicit SandboxTestingChild(SandboxTestingThread* aThread, + Endpoint&& aEndpoint); + void Bind(Endpoint&& aEndpoint); + UniquePtr mThread; static SandboxTestingChild* sInstance; diff --git a/security/sandbox/common/test/SandboxTestingChildTests.h b/security/sandbox/common/test/SandboxTestingChildTests.h new file mode 100644 index 000000000000..20a1b1ee1f82 --- /dev/null +++ b/security/sandbox/common/test/SandboxTestingChildTests.h @@ -0,0 +1,95 @@ +/* -*- 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 "nsXULAppAPI.h" + +#ifdef XP_UNIX +# include +# include +# ifdef XP_LINUX +# include +# endif // XP_LINUX +# include +# include +# include +# include +# include +#endif + +namespace mozilla { + +void RunTestsContent(SandboxTestingChild* child) { + MOZ_ASSERT(child, "No SandboxTestingChild*?"); + +#ifdef XP_UNIX + struct stat st; + static const char kAllowedPath[] = "/usr/lib"; + + child->ErrnoTest("fstatat_as_stat"_ns, true, + [&] { return fstatat(AT_FDCWD, kAllowedPath, &st, 0); }); + child->ErrnoTest("fstatat_as_lstat"_ns, true, [&] { + return fstatat(AT_FDCWD, kAllowedPath, &st, AT_SYMLINK_NOFOLLOW); + }); + +# ifdef XP_LINUX + child->ErrnoTest("fstatat_as_fstat"_ns, true, + [&] { return fstatat(0, "", &st, AT_EMPTY_PATH); }); +# endif // XP_LINUX + + const struct timespec usec = {0, 1000}; + child->ErrnoTest("nanosleep"_ns, true, + [&] { return nanosleep(&usec, nullptr); }); + + struct timespec res = {0, 0}; + child->ErrnoTest("clock_getres"_ns, true, + [&] { return clock_getres(CLOCK_REALTIME, &res); }); + +#else // XP_UNIX + child->SendReportTestResults( + "dummy_test"_ns, + /* shouldSucceed */ true, + /* didSucceed */ true, + "The test framework fails if there are no cases."_ns); +#endif // XP_UNIX +} + +void RunTestsSocket(SandboxTestingChild* child) { + MOZ_ASSERT(child, "No SandboxTestingChild*?"); + +#ifdef XP_UNIX + child->ErrnoTest("getaddrinfo"_ns, true, [&] { + struct addrinfo* res; + int rv = getaddrinfo("localhost", nullptr, nullptr, &res); + if (res != nullptr) { + freeaddrinfo(res); + } + return rv; + }); + +# ifdef XP_LINUX + child->ErrnoTest("prctl_allowed"_ns, true, [&] { + int rv = prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); + return rv; + }); + + child->ErrnoTest("prctl_blocked"_ns, false, [&] { + int rv = prctl(PR_GET_SECCOMP, 0, 0, 0, 0); + return rv; + }); +# endif // XP_LINUX + +#else // XP_UNIX + child->SendReportTestResults( + "dummy_test"_ns, + /* shouldSucceed */ true, + /* didSucceed */ true, + "The test framework fails if there are no cases."_ns); +#endif // XP_UNIX +} + +} // namespace mozilla diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp index 354866ef9374..8d9cd9f8d94f 100644 --- a/security/sandbox/linux/Sandbox.cpp +++ b/security/sandbox/linux/Sandbox.cpp @@ -83,7 +83,7 @@ mozilla::Atomic gSeccompTsyncBroadcastSignum(0); namespace mozilla { -static bool gSandboxCrashOnError = false; +static mozilla::Atomic gSandboxCrashOnError(false); // This is initialized by SandboxSetCrashFunc(). SandboxCrashFunc gSandboxCrashFunc; @@ -709,4 +709,10 @@ void SetSocketProcessSandbox(int aBroker) { SetCurrentProcessSandbox(GetSocketProcessSandboxPolicy(sBroker)); } +bool SetSandboxCrashOnError(bool aValue) { + bool oldValue = gSandboxCrashOnError; + gSandboxCrashOnError = aValue; + return oldValue; +} + } // namespace mozilla diff --git a/security/sandbox/linux/Sandbox.h b/security/sandbox/linux/Sandbox.h index 193fd89c29ea..d60eaa3d7ffe 100644 --- a/security/sandbox/linux/Sandbox.h +++ b/security/sandbox/linux/Sandbox.h @@ -63,6 +63,10 @@ MOZ_EXPORT void SetRemoteDataDecoderSandbox(int aBroker); MOZ_EXPORT void SetSocketProcessSandbox(int aBroker); +// We want to turn on/off crashing on error when running some tests +// This will return current value and set the aValue we pass +MOZ_EXPORT bool SetSandboxCrashOnError(bool aValue); + } // namespace mozilla #endif // mozilla_Sandbox_h diff --git a/security/sandbox/test/browser_sandbox_test.js b/security/sandbox/test/browser_sandbox_test.js index 2c4af40ca84e..bd8cbc04fd5b 100644 --- a/security/sandbox/test/browser_sandbox_test.js +++ b/security/sandbox/test/browser_sandbox_test.js @@ -11,7 +11,10 @@ function test() { ); // Types of processes to test, taken from GeckoProcessTypes.h - var processTypes = ["tab", "gpu"]; + // GPU process might not run depending on the platform, so we need it to be + // the last one of the list to allow the remainingTests logic below to work + // as expected. + var processTypes = ["tab", "socket", "gpu"]; // A callback called after each test-result. Services.obs.addObserver(function result(subject, topic, data) {