Skip to content

Commit 1ff75e4

Browse files
committed
[scudo] verify free'd secondary was allocated before
1 parent 912506b commit 1ff75e4

File tree

4 files changed

+163
-0
lines changed

4 files changed

+163
-0
lines changed

compiler-rt/lib/scudo/standalone/allocator_config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ struct DefaultConfig {
153153
static const s32 MinReleaseToOsIntervalMs = INT32_MIN;
154154
static const s32 MaxReleaseToOsIntervalMs = INT32_MAX;
155155
};
156+
static const bool VerifyInUseAddresses = true;
157+
static const u32 InUseBlocksSize = 1000U;
156158
template <typename Config> using CacheT = MapAllocatorCache<Config>;
157159
};
158160

@@ -198,6 +200,8 @@ struct AndroidConfig {
198200
static const s32 MinReleaseToOsIntervalMs = 0;
199201
static const s32 MaxReleaseToOsIntervalMs = 1000;
200202
};
203+
static const bool VerifyInUseAddresses = true;
204+
static const u32 InUseBlocksSize = 1000U;
201205
template <typename Config> using CacheT = MapAllocatorCache<Config>;
202206
};
203207

@@ -230,6 +234,8 @@ struct FuchsiaConfig {
230234
template <typename Config> using PrimaryT = SizeClassAllocator64<Config>;
231235

232236
struct Secondary {
237+
static const bool VerifyInUseAddresses = true;
238+
static const u32 InUseBlocksSize = 1000U;
233239
template <typename Config> using CacheT = MapAllocatorNoCache<Config>;
234240
};
235241
template <typename Config> using SecondaryT = MapAllocator<Config>;
@@ -254,6 +260,8 @@ struct TrustyConfig {
254260
template <typename Config> using PrimaryT = SizeClassAllocator64<Config>;
255261

256262
struct Secondary {
263+
static const bool VerifyInUseAddresses = true;
264+
static const u32 InUseBlocksSize = 1000U;
257265
template <typename Config> using CacheT = MapAllocatorNoCache<Config>;
258266
};
259267

compiler-rt/lib/scudo/standalone/secondary.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "chunk.h"
1313
#include "common.h"
14+
#include "internal_defs.h"
1415
#include "list.h"
1516
#include "mem_map.h"
1617
#include "memtag.h"
@@ -476,6 +477,23 @@ template <typename Config> class MapAllocator {
476477
DCHECK_EQ(FreedBytes, 0U);
477478
Cache.init(ReleaseToOsInterval);
478479
Stats.init();
480+
481+
if (Config::Secondary::VerifyInUseAddresses) {
482+
ReservedMemoryT InUseReserved;
483+
InUseReserved.create(
484+
0U, sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1),
485+
"scudo:secondary_integrity");
486+
DCHECK_NE(InUseReserved.getBase(), 0U);
487+
488+
InUseAddresses = InUseReserved.dispatch(
489+
InUseReserved.getBase(),
490+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1));
491+
CHECK(InUseAddresses.isAllocated());
492+
InUseAddresses.setMemoryPermission(
493+
InUseAddresses.getBase(),
494+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1), 0);
495+
}
496+
479497
if (LIKELY(S))
480498
S->link(&Stats);
481499
}
@@ -544,6 +562,8 @@ template <typename Config> class MapAllocator {
544562
u32 NumberOfAllocs GUARDED_BY(Mutex) = 0;
545563
u32 NumberOfFrees GUARDED_BY(Mutex) = 0;
546564
LocalStats Stats GUARDED_BY(Mutex);
565+
566+
MemMapT InUseAddresses GUARDED_BY(Mutex) = {};
547567
};
548568

549569
// As with the Primary, the size passed to this function includes any desired
@@ -588,6 +608,54 @@ void *MapAllocator<Config>::allocate(const Options &Options, uptr Size,
588608
BlockEnd - PtrInt);
589609
{
590610
ScopedLock L(Mutex);
611+
612+
if (Config::Secondary::VerifyInUseAddresses) {
613+
void **IntegrityList =
614+
reinterpret_cast<void **>(InUseAddresses.getBase());
615+
bool isFull = true;
616+
bool reachedEnd = false;
617+
618+
while (!reachedEnd) {
619+
for (u32 I = 0; I < Config::Secondary::InUseBlocksSize; I++) {
620+
if (IntegrityList[I] == nullptr) {
621+
isFull = false;
622+
IntegrityList[I] = Ptr;
623+
break;
624+
}
625+
}
626+
if (isFull &&
627+
IntegrityList[Config::Secondary::InUseBlocksSize] != nullptr) {
628+
IntegrityList = static_cast<void **>(
629+
IntegrityList[Config::Secondary::InUseBlocksSize]);
630+
} else {
631+
reachedEnd = true;
632+
}
633+
}
634+
635+
if (isFull) {
636+
ReservedMemoryT InUseReserved;
637+
InUseReserved.create(
638+
0U, sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1),
639+
"scudo:secondary_integrity");
640+
DCHECK_NE(InUseReserved.getBase(), 0U);
641+
642+
MemMapT NewAddresses = InUseReserved.dispatch(
643+
InUseReserved.getBase(),
644+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1));
645+
CHECK(NewAddresses.isAllocated());
646+
NewAddresses.setMemoryPermission(
647+
NewAddresses.getBase(),
648+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1), 0);
649+
650+
IntegrityList[Config::Secondary::InUseBlocksSize] =
651+
reinterpret_cast<void *>(NewAddresses.getBase());
652+
653+
IntegrityList = static_cast<void **>(
654+
IntegrityList[Config::Secondary::InUseBlocksSize]);
655+
IntegrityList[0] = Ptr;
656+
}
657+
}
658+
591659
InUseBlocks.push_back(H);
592660
AllocatedBytes += H->CommitSize;
593661
FragmentedBytes += H->MemMap.getCapacity() - H->CommitSize;
@@ -662,6 +730,56 @@ void *MapAllocator<Config>::allocate(const Options &Options, uptr Size,
662730
*BlockEndPtr = CommitBase + CommitSize;
663731
{
664732
ScopedLock L(Mutex);
733+
734+
if (Config::Secondary::VerifyInUseAddresses) {
735+
void **IntegrityList =
736+
reinterpret_cast<void **>(InUseAddresses.getBase());
737+
bool isFull = true;
738+
bool reachedEnd = false;
739+
740+
while (!reachedEnd) {
741+
for (u32 I = 0; I < Config::Secondary::InUseBlocksSize; I++) {
742+
if (IntegrityList[I] == nullptr) {
743+
isFull = false;
744+
IntegrityList[I] = reinterpret_cast<void *>(
745+
HeaderPos + LargeBlock::getHeaderSize());
746+
break;
747+
}
748+
}
749+
if (isFull &&
750+
IntegrityList[Config::Secondary::InUseBlocksSize] != nullptr) {
751+
IntegrityList = static_cast<void **>(
752+
IntegrityList[Config::Secondary::InUseBlocksSize]);
753+
} else {
754+
reachedEnd = true;
755+
}
756+
}
757+
758+
if (isFull) {
759+
ReservedMemoryT InUseReserved;
760+
InUseReserved.create(
761+
0U, sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1),
762+
"scudo:secondary_integrity");
763+
DCHECK_NE(InUseReserved.getBase(), 0U);
764+
765+
MemMapT NewAddresses = InUseReserved.dispatch(
766+
InUseReserved.getBase(),
767+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1));
768+
CHECK(NewAddresses.isAllocated());
769+
NewAddresses.setMemoryPermission(
770+
NewAddresses.getBase(),
771+
sizeof(void *) * (Config::Secondary::InUseBlocksSize + 1), 0);
772+
773+
IntegrityList[Config::Secondary::InUseBlocksSize] =
774+
reinterpret_cast<void *>(NewAddresses.getBase());
775+
776+
IntegrityList = static_cast<void **>(
777+
IntegrityList[Config::Secondary::InUseBlocksSize]);
778+
IntegrityList[0] =
779+
reinterpret_cast<void *>(HeaderPos + LargeBlock::getHeaderSize());
780+
}
781+
}
782+
665783
InUseBlocks.push_back(H);
666784
AllocatedBytes += CommitSize;
667785
FragmentedBytes += H->MemMap.getCapacity() - CommitSize;
@@ -681,6 +799,35 @@ void MapAllocator<Config>::deallocate(const Options &Options, void *Ptr)
681799
const uptr CommitSize = H->CommitSize;
682800
{
683801
ScopedLock L(Mutex);
802+
803+
if (Config::Secondary::VerifyInUseAddresses) {
804+
void **IntegrityList =
805+
reinterpret_cast<void **>(InUseAddresses.getBase());
806+
bool isValid = false;
807+
bool reachedEnd = false;
808+
809+
while (!reachedEnd) {
810+
for (u32 I = 0; I < Config::Secondary::InUseBlocksSize; I++) {
811+
if (IntegrityList[I] == Ptr) {
812+
isValid = true;
813+
IntegrityList[I] = nullptr;
814+
break;
815+
}
816+
}
817+
if (!isValid &&
818+
IntegrityList[Config::Secondary::InUseBlocksSize] != nullptr) {
819+
IntegrityList = static_cast<void **>(
820+
IntegrityList[Config::Secondary::InUseBlocksSize]);
821+
} else {
822+
reachedEnd = true;
823+
}
824+
}
825+
826+
if (!isValid) {
827+
return;
828+
}
829+
}
830+
684831
InUseBlocks.remove(H);
685832
FreedBytes += CommitSize;
686833
FragmentedBytes -= H->MemMap.getCapacity() - CommitSize;

compiler-rt/lib/scudo/standalone/tests/combined_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ struct TestConditionVariableConfig {
205205
#endif
206206

207207
struct Secondary {
208+
static const bool VerifyInUseAddresses = true;
209+
static const scudo::u32 InUseBlocksSize = 1000U;
208210
template <typename Config>
209211
using CacheT = scudo::MapAllocatorNoCache<Config>;
210212
};
@@ -678,6 +680,8 @@ struct DeathConfig {
678680
using PrimaryT = scudo::SizeClassAllocator64<Config>;
679681

680682
struct Secondary {
683+
static const bool VerifyInUseAddresses = true;
684+
static const scudo::u32 InUseBlocksSize = 1000U;
681685
template <typename Config>
682686
using CacheT = scudo::MapAllocatorNoCache<Config>;
683687
};

compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ template <typename Config> static void testSecondaryBasic(void) {
8585
struct NoCacheConfig {
8686
static const bool MaySupportMemoryTagging = false;
8787
struct Secondary {
88+
static const bool VerifyInUseAddresses = true;
89+
static const scudo::u32 InUseBlocksSize = 1000U;
8890
template <typename Config>
8991
using CacheT = scudo::MapAllocatorNoCache<Config>;
9092
};
@@ -102,6 +104,8 @@ struct TestConfig {
102104
static const scudo::s32 MaxReleaseToOsIntervalMs = INT32_MAX;
103105
};
104106

107+
static const bool VerifyInUseAddresses = true;
108+
static const scudo::u32 InUseBlocksSize = 1000U;
105109
template <typename Config> using CacheT = scudo::MapAllocatorCache<Config>;
106110
};
107111
};

0 commit comments

Comments
 (0)