/* -*- 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 http://mozilla.org/MPL/2.0/. */ #include "nsThreadUtils.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/DebugOnly.h" #include "mozilla/RLBoxSandboxPool.h" #ifdef MOZ_USING_WASM_SANDBOXING # include "mozilla/rlbox/rlbox_config.h" # include "mozilla/rlbox/rlbox_wasm2c_sandbox.hpp" #endif using namespace mozilla; NS_IMPL_ISUPPORTS(RLBoxSandboxPool, nsITimerCallback, nsINamed) void RLBoxSandboxPool::StartTimer() { mMutex.AssertCurrentThreadOwns(); MOZ_ASSERT(!mTimer, "timer already initialized"); if (NS_IsMainThread() && PastShutdownPhase(ShutdownPhase::AppShutdownConfirmed)) { // If we're shutting down, setting the time might fail, and we don't need it // (since all the memory will be cleaned up soon anyway). Note that // PastShutdownPhase() can only be called on the main thread, but that's // fine, because other threads will have joined already by the point timers // start failing to register. mPool.Clear(); return; } DebugOnly rv = NS_NewTimerWithCallback( getter_AddRefs(mTimer), this, mDelaySeconds * 1000, nsITimer::TYPE_ONE_SHOT, GetMainThreadEventTarget()); MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create timer"); } void RLBoxSandboxPool::CancelTimer() { mMutex.AssertCurrentThreadOwns(); if (mTimer) { mTimer->Cancel(); mTimer = nullptr; } } NS_IMETHODIMP RLBoxSandboxPool::Notify(nsITimer* aTimer) { MutexAutoLock lock(mMutex); mPool.Clear(); mTimer = nullptr; return NS_OK; } NS_IMETHODIMP RLBoxSandboxPool::GetName(nsACString& aName) { aName.AssignLiteral("RLBoxSandboxPool"); return NS_OK; } void RLBoxSandboxPool::Push(UniquePtr sbxData) { MutexAutoLock lock(mMutex); mPool.AppendElement(std::move(sbxData)); if (!mTimer) { StartTimer(); } } UniquePtr RLBoxSandboxPool::PopOrCreate( uint64_t aMinSize) { MutexAutoLock lock(mMutex); UniquePtr sbxData; if (!mPool.IsEmpty()) { const int64_t lastIndex = ReleaseAssertedCast(mPool.Length()) - 1; for (int64_t i = lastIndex; i >= 0; i--) { if (mPool[i]->mSize >= aMinSize) { sbxData = std::move(mPool[i]); mPool.RemoveElementAt(i); // If we reuse a sandbox from the pool, reset the timer to clear the // pool CancelTimer(); if (!mPool.IsEmpty()) { StartTimer(); } break; } } } if (!sbxData) { #ifdef MOZ_USING_WASM_SANDBOXING // RLBox's wasm sandboxes have a limited platform dependent capacity. We // track this capacity in this pool. Note the noop sandboxes have no // capacity limit but this design assumes that all sandboxes use the wasm // sandbox limit. const uint64_t defaultCapacityForSandbox = wasm_rt_get_default_max_linear_memory_size(); const uint64_t minSandboxCapacity = std::max(aMinSize, defaultCapacityForSandbox); const uint64_t chosenAdjustedCapacity = rlbox::rlbox_wasm2c_sandbox::rlbox_wasm2c_get_adjusted_heap_size( minSandboxCapacity); #else // If sandboxing is disabled altogether we just set a limit of 4gb. // This is not actually enforced by the noop sandbox. const uint64_t chosenAdjustedCapacity = static_cast(1) << 32; #endif sbxData = CreateSandboxData(chosenAdjustedCapacity); NS_ENSURE_TRUE(sbxData, nullptr); } return MakeUnique(std::move(sbxData), this); }