blob: f5c668dcea72952dbe7463448ae0284a3b2fc6b1 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <sys/mman.h>
#include <unistd.h>
#include <gtest/gtest.h>
#include "src/starnix/tests/syscalls/cpp/test_helper.h"
#if defined(__x86_64__)
// Source: //zircon/kernel/arch/x86/include/arch/kernel_aspace.h
#define LOWEST_MAPPABLE_ADDRESS ((uintptr_t)0x200000)
#define HIGHEST_MAPPABLE_ADDRESS ((uintptr_t)(1ULL << 46))
#elif defined(__aarch64__)
// Source: //zircon/kernel/arch/arm64/include/arch/kernel_aspace.h
#define LOWEST_MAPPABLE_ADDRESS ((uintptr_t)0x200000)
#define HIGHEST_MAPPABLE_ADDRESS ((uintptr_t)(1ULL << 47))
#elif defined(__arm)
// Arch32 can only address 4GB
#define LOWEST_MAPPABLE_ADDRESS ((uintptr_t)0x200000)
#define HIGHEST_MAPPABLE_ADDRESS ((uintptr_t)(0xffff0000))
// Source: //zircon/kernel/arch/riscv64/include/arch/kernel_aspace.h
#elif defined(__riscv)
// Assuming Sv39 on RISC-V as we do not currently support any other addressing modes.
#define LOWEST_MAPPABLE_ADDRESS ((uintptr_t)0x200000)
#define HIGHEST_MAPPABLE_ADDRESS ((uintptr_t)(1ULL << 37))
#endif
struct TestAddress {
uintptr_t address;
bool upper_bound;
};
class AspaceTest : public testing::TestWithParam<TestAddress> {
protected:
uintptr_t test_mapping_base_address() const {
if (GetParam().upper_bound) {
// The page containing the upper bound of the address space starts one page before
// the upper bound address.
const size_t page_size = SAFE_SYSCALL(sysconf(_SC_PAGE_SIZE));
return GetParam().address - page_size;
} else {
return GetParam().address;
}
}
};
TEST_P(AspaceTest, RangeFault) {
// Create a read-only mapping at the target address.
const size_t page_size = SAFE_SYSCALL(sysconf(_SC_PAGE_SIZE));
void* mapped = mmap(reinterpret_cast<void*>(test_mapping_base_address()), page_size, PROT_READ,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
ASSERT_NE(mapped, MAP_FAILED);
int pipefd[2];
SAFE_SYSCALL(pipe(pipefd));
char buf[] = {'a'};
write(pipefd[1], buf, sizeof(buf));
// Induce a kernel-mode write to the mapped memory.
// This should trigger a page fault caught by Starnix.
EXPECT_EQ(read(pipefd[0], mapped, 1), -1);
EXPECT_EQ(errno, EFAULT);
// Reads from this address should work fine.
EXPECT_EQ(write(pipefd[1], mapped, 1), 1);
}
INSTANTIATE_TEST_SUITE_P(LowestAddress, AspaceTest,
testing::Values(TestAddress{.address = LOWEST_MAPPABLE_ADDRESS,
.upper_bound = false}));
INSTANTIATE_TEST_SUITE_P(HighestAddress, AspaceTest,
testing::Values(TestAddress{.address = HIGHEST_MAPPABLE_ADDRESS,
.upper_bound = true}));