0

[BRP] Make sure poisoned pointers are invalid

When a 32-bit process runs on a 64-bit operating system, the address
that is made by repeating the quarantine byte may be available for
mapping.

Reserve a memory region at that address during the process startup and
make it not readable or writable so that an attempt to follow a pointer
from a quarantined object will always result in a crash.

Change-Id: Ide9ee111ac9a6394a3a17ec0808436b184f17b20
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3988206
Commit-Queue: Sergei Glazunov <glazunov@google.com>
Reviewed-by: Bartek Nowierski <bartekn@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1064864}
This commit is contained in:
Sergei Glazunov
2022-10-28 16:06:44 +00:00
committed by Chromium LUCI CQ
parent 51b3c4fd33
commit 138f020da4
2 changed files with 49 additions and 0 deletions
base/allocator/partition_allocator

@ -3940,6 +3940,25 @@ TEST_P(UnretainedDanglingRawPtrTest, UnretainedDanglingPtrShouldReport) {
EXPECT_TRUE(ref_count->Release());
}
#if !defined(PA_HAS_64_BITS_POINTERS)
TEST_P(PartitionAllocTest, BackupRefPtrGuardRegion) {
size_t alignment = internal::PageAllocationGranularity();
uintptr_t requested_address;
memset(&requested_address, internal::kQuarantinedByte,
sizeof(requested_address));
requested_address = RoundDownToPageAllocationGranularity(requested_address);
uintptr_t allocated_address = AllocPages(
requested_address, alignment, alignment,
PageAccessibilityConfiguration::kReadWrite, PageTag::kPartitionAlloc);
CHECK_NE(allocated_address, requested_address);
if (allocated_address) {
FreePages(allocated_address, alignment);
}
}
#endif // !defined(PA_HAS_64_BITS_POINTERS)
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)

@ -230,6 +230,34 @@ void AfterForkInChild() {
}
#endif // defined(PA_HAS_ATFORK_HANDLER)
// An address constructed by repeating `kQuarantinedByte` shouldn't never point
// to valid memory. Preemptively reserve a memory region around that address and
// make it inaccessible. Not needed for 64-bit platforms where the address is
// guaranteed to be non-canonical.
void ReserveBackupRefPtrGuardRegionIfNeeded() {
#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && \
!defined(PA_HAS_64_BITS_POINTERS)
size_t alignment = internal::PageAllocationGranularity();
uintptr_t requested_address;
memset(&requested_address, internal::kQuarantinedByte,
sizeof(requested_address));
requested_address = RoundDownToPageAllocationGranularity(requested_address);
// Request several pages so that even unreasonably large C++ objects stay
// within the inaccessible region. If some of the pages can't be reserved,
// it's still preferable to try and reserve the rest.
for (size_t i = 0; i < 4; ++i) {
[[maybe_unused]] uintptr_t allocated_address =
AllocPages(requested_address, alignment, alignment,
PageAccessibilityConfiguration::kInaccessible,
PageTag::kPartitionAlloc);
requested_address += alignment;
}
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) &&
// !defined(PA_HAS_64_BITS_POINTERS)
}
std::atomic<bool> g_global_init_called;
void PartitionAllocMallocInitOnce() {
bool expected = false;
@ -264,6 +292,8 @@ void PartitionAllocMallocInitOnce() {
pthread_atfork(BeforeForkInParent, AfterForkInParent, AfterForkInChild);
PA_CHECK(err == 0);
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ReserveBackupRefPtrGuardRegionIfNeeded();
}
} // namespace