[ASan] Fix missed poisoned suffix in first granule in __asan_region_is_poisoned (#187466)
Align beg address down instead of up in __asan_region_is_poisoned(), so the shadow scan includes the first granule. This fixes a false negative when first granule has an unpoisoned prefix and poisoned suffix. Add test that covers this scenario.
This commit is contained in:
parent
d7dbba55bf
commit
ca54948d0b
@ -247,16 +247,15 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) {
|
||||
if (!AddrIsInMem(last))
|
||||
return last;
|
||||
CHECK_LE(beg, last);
|
||||
// First check the first and the last application bytes,
|
||||
// then check the ASAN_SHADOW_GRANULARITY-aligned inner region by calling
|
||||
// mem_is_zero on the corresponding shadow.
|
||||
if (!__asan::AddressIsPoisoned(beg) && !__asan::AddressIsPoisoned(last)) {
|
||||
uptr aligned_b = RoundUpTo(beg, ASAN_SHADOW_GRANULARITY);
|
||||
// First check the last application byte, i.e. last granule, then check
|
||||
// the ASAN_SHADOW_GRANULARITY-aligned region by calling mem_is_zero
|
||||
// on the corresponding shadow (first granule is fully checked).
|
||||
if (!__asan::AddressIsPoisoned(last)) {
|
||||
uptr aligned_b = RoundDownTo(beg, ASAN_SHADOW_GRANULARITY);
|
||||
uptr aligned_e = RoundDownTo(last, ASAN_SHADOW_GRANULARITY);
|
||||
if (aligned_e <= aligned_b)
|
||||
return 0;
|
||||
if (UNLIKELY(aligned_b < beg)) // address space overflow.
|
||||
if (aligned_b == aligned_e) // one granule case => last check is enough.
|
||||
return 0;
|
||||
CHECK_LT(aligned_b, aligned_e);
|
||||
uptr shadow_beg = MemToShadow(aligned_b);
|
||||
uptr shadow_end = MemToShadow(aligned_e);
|
||||
CHECK_LT(shadow_beg, shadow_end);
|
||||
|
||||
@ -200,6 +200,40 @@ TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, PoisonedSuffixOfFirstGranuleOfRegionTest) {
|
||||
static const size_t granularity = 1ULL << 3; // shadow granularity
|
||||
char* array = Ident((char*)malloc(118));
|
||||
// State: [0..117] - unpoisoned
|
||||
char* first_granule = (char*)((uintptr_t)array & ~(granularity - 1));
|
||||
EXPECT_EQ(array, first_granule);
|
||||
// Poison [4..7] (suffix of the first granule)
|
||||
__asan_poison_memory_region(array + 4, 4);
|
||||
// State: [uuuupppp][uuuuuuuu]...[uuuuuupp]
|
||||
// i.e. [0..3] - unpoisoned; [4..7] - poisoned; [8..117] - unpoisoned
|
||||
// Sanity checks:
|
||||
GOOD_ACCESS(array, 3);
|
||||
BAD_ACCESS(array, 4);
|
||||
BAD_ACCESS(array, 7);
|
||||
GOOD_ACCESS(array, 8);
|
||||
GOOD_ACCESS(array, 117);
|
||||
BAD_ACCESS(array, 118);
|
||||
EXPECT_EQ(0, __asan_region_is_poisoned(array, 4)); // [0..3]
|
||||
EXPECT_EQ(0, __asan_region_is_poisoned(array + 8, 110)); // [8..117]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 4, 4)); // [4..7]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array, 8)); // [0..7]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array, 16)); // [0..15]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array, 17)); // [0..16]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 4, 12)); // [4..15]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 4, 13)); // [4..16]
|
||||
EXPECT_EQ(array + 5, __asan_region_is_poisoned(array + 5, 2)); // [5..6]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 2, 4)); // [2..5]
|
||||
EXPECT_EQ(array + 6, __asan_region_is_poisoned(array + 6, 10)); // [6..15]
|
||||
// Check that poisoned suffix of the first granule is not skipped:
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 2, 14)); // [2..15]
|
||||
EXPECT_EQ(array + 4, __asan_region_is_poisoned(array + 2, 100)); // [2..101]
|
||||
free(array);
|
||||
}
|
||||
|
||||
TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
|
||||
// Vector of capacity 20
|
||||
char *vec = Ident((char*)malloc(20));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user