f43f8a0bb5
Instead of returning a boolean success/failure value, the Free* methods of the VirtualAddressSpace API now terminate the process on failure, as this implies a bug in the caller. This is simpler than CHECKing for success in all callers and also provides more details about the possible cause of the failure. Bug: v8:12656 Change-Id: I5b469ae2c564068cff74e60b7e98f6a4776a239d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3506992 Reviewed-by: Clemens Backes <clemensb@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Samuel Groß <saelo@chromium.org> Cr-Commit-Position: refs/heads/main@{#79388}
156 lines
4.4 KiB
C++
156 lines
4.4 KiB
C++
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/sandbox/sandbox.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "src/base/virtual-address-space.h"
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
#ifdef V8_SANDBOX_IS_AVAILABLE
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
TEST(SandboxTest, Initialization) {
|
|
base::VirtualAddressSpace vas;
|
|
|
|
Sandbox sandbox;
|
|
|
|
EXPECT_FALSE(sandbox.is_initialized());
|
|
EXPECT_FALSE(sandbox.is_disabled());
|
|
EXPECT_FALSE(sandbox.is_partially_reserved());
|
|
EXPECT_EQ(sandbox.size(), 0UL);
|
|
|
|
EXPECT_TRUE(sandbox.Initialize(&vas));
|
|
|
|
EXPECT_TRUE(sandbox.is_initialized());
|
|
EXPECT_NE(sandbox.base(), 0UL);
|
|
EXPECT_GT(sandbox.size(), 0UL);
|
|
|
|
sandbox.TearDown();
|
|
|
|
EXPECT_FALSE(sandbox.is_initialized());
|
|
}
|
|
|
|
TEST(SandboxTest, InitializationWithSize) {
|
|
base::VirtualAddressSpace vas;
|
|
// This test only works if virtual memory subspaces can be allocated.
|
|
if (!vas.CanAllocateSubspaces()) return;
|
|
|
|
Sandbox sandbox;
|
|
size_t size = kSandboxMinimumSize;
|
|
const bool use_guard_regions = false;
|
|
EXPECT_TRUE(sandbox.Initialize(&vas, size, use_guard_regions));
|
|
|
|
EXPECT_TRUE(sandbox.is_initialized());
|
|
EXPECT_FALSE(sandbox.is_partially_reserved());
|
|
EXPECT_EQ(sandbox.size(), size);
|
|
|
|
sandbox.TearDown();
|
|
}
|
|
|
|
TEST(SandboxTest, PartiallyReservedSandboxInitialization) {
|
|
base::VirtualAddressSpace vas;
|
|
Sandbox sandbox;
|
|
// Total size of the sandbox.
|
|
size_t size = kSandboxSize;
|
|
// Size of the virtual memory that is actually reserved at the start of the
|
|
// sandbox.
|
|
size_t reserved_size = 2 * vas.allocation_granularity();
|
|
EXPECT_TRUE(
|
|
sandbox.InitializeAsPartiallyReservedSandbox(&vas, size, reserved_size));
|
|
|
|
EXPECT_TRUE(sandbox.is_initialized());
|
|
EXPECT_TRUE(sandbox.is_partially_reserved());
|
|
EXPECT_NE(sandbox.base(), 0UL);
|
|
EXPECT_EQ(sandbox.size(), size);
|
|
|
|
sandbox.TearDown();
|
|
|
|
EXPECT_FALSE(sandbox.is_initialized());
|
|
}
|
|
|
|
TEST(SandboxTest, Contains) {
|
|
base::VirtualAddressSpace vas;
|
|
Sandbox sandbox;
|
|
EXPECT_TRUE(sandbox.Initialize(&vas));
|
|
|
|
Address base = sandbox.base();
|
|
size_t size = sandbox.size();
|
|
base::RandomNumberGenerator rng(::testing::FLAGS_gtest_random_seed);
|
|
|
|
EXPECT_TRUE(sandbox.Contains(base));
|
|
EXPECT_TRUE(sandbox.Contains(base + size - 1));
|
|
for (int i = 0; i < 10; i++) {
|
|
size_t offset = rng.NextInt64() % size;
|
|
EXPECT_TRUE(sandbox.Contains(base + offset));
|
|
}
|
|
|
|
EXPECT_FALSE(sandbox.Contains(base - 1));
|
|
EXPECT_FALSE(sandbox.Contains(base + size));
|
|
for (int i = 0; i < 10; i++) {
|
|
Address addr = rng.NextInt64();
|
|
if (addr < base || addr >= base + size) {
|
|
EXPECT_FALSE(sandbox.Contains(addr));
|
|
}
|
|
}
|
|
|
|
sandbox.TearDown();
|
|
}
|
|
|
|
void TestPageAllocationInSandbox(Sandbox& sandbox) {
|
|
const size_t kAllocatinSizesInPages[] = {1, 1, 2, 3, 5, 8, 13, 21, 34};
|
|
constexpr int kNumAllocations = arraysize(kAllocatinSizesInPages);
|
|
|
|
VirtualAddressSpace* vas = sandbox.address_space();
|
|
size_t allocation_granularity = vas->allocation_granularity();
|
|
std::vector<Address> allocations;
|
|
for (int i = 0; i < kNumAllocations; i++) {
|
|
size_t length = allocation_granularity * kAllocatinSizesInPages[i];
|
|
size_t alignment = allocation_granularity;
|
|
Address ptr = vas->AllocatePages(VirtualAddressSpace::kNoHint, length,
|
|
alignment, PagePermissions::kNoAccess);
|
|
EXPECT_NE(ptr, kNullAddress);
|
|
EXPECT_TRUE(sandbox.Contains(ptr));
|
|
allocations.push_back(ptr);
|
|
}
|
|
|
|
for (int i = 0; i < kNumAllocations; i++) {
|
|
size_t length = allocation_granularity * kAllocatinSizesInPages[i];
|
|
vas->FreePages(allocations[i], length);
|
|
}
|
|
}
|
|
|
|
TEST(SandboxTest, PageAllocation) {
|
|
base::VirtualAddressSpace vas;
|
|
Sandbox sandbox;
|
|
EXPECT_TRUE(sandbox.Initialize(&vas));
|
|
|
|
TestPageAllocationInSandbox(sandbox);
|
|
|
|
sandbox.TearDown();
|
|
}
|
|
|
|
TEST(SandboxTest, PartiallyReservedSandboxPageAllocation) {
|
|
base::VirtualAddressSpace vas;
|
|
Sandbox sandbox;
|
|
size_t size = kSandboxSize;
|
|
// Only reserve two pages so the test will allocate memory inside and outside
|
|
// of the reserved region.
|
|
size_t reserved_size = 2 * vas.allocation_granularity();
|
|
EXPECT_TRUE(
|
|
sandbox.InitializeAsPartiallyReservedSandbox(&vas, size, reserved_size));
|
|
|
|
TestPageAllocationInSandbox(sandbox);
|
|
|
|
sandbox.TearDown();
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_SANDBOX_IS_AVAILABLE
|