[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:

committed by
Chromium LUCI CQ

parent
51b3c4fd33
commit
138f020da4
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
|
||||
|
Reference in New Issue
Block a user