[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
//===-- scudo_allocator.h ---------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// Header for scudo_allocator.cpp.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef SCUDO_ALLOCATOR_H_
|
|
|
|
#define SCUDO_ALLOCATOR_H_
|
|
|
|
|
[scudo] Scudo thread specific data refactor, part 3
Summary:
Previous parts: D38139, D38183.
In this part of the refactor, we abstract the Linux vs Android TSD dissociation
in favor of a Exclusive vs Shared one, allowing for easier platform introduction
and configuration.
Most of this change consist of shuffling the files around to reflect the new
organization.
We introduce `scudo_platform.h` where platform specific definition lie. This
involves the TSD model and the platform specific allocator parameters. In an
upcoming CL, those will be configurable via defines, but we currently stick
with conservative defaults.
Reviewers: alekseyshl, dvyukov
Reviewed By: alekseyshl, dvyukov
Subscribers: srhines, llvm-commits, mgorny
Differential Revision: https://reviews.llvm.org/D38244
llvm-svn: 314224
2017-09-27 01:20:02 +08:00
|
|
|
#include "scudo_platform.h"
|
[scudo] Refactor of CRC32 and ARM runtime CRC32 detection
Summary:
ARM & AArch64 runtime detection for hardware support of CRC32 has been added
via check of the AT_HWVAL auxiliary vector.
Following Michal's suggestions in D28417, the CRC32 code has been further
changed and looks better now. When compiled with full relro (which is strongly
suggested to benefit from additional hardening), the weak symbol for
computeHardwareCRC32 is read-only and the assembly generated is fairly clean
and straight forward. As suggested, an additional optimization is to skip
the runtime check if SSE 4.2 has been enabled globally, as opposed to only
for scudo_crc32.cpp.
scudo_crc32.h has no purpose anymore and was removed.
Reviewers: alekseyshl, kcc, rengolin, mgorny, phosek
Reviewed By: rengolin, mgorny
Subscribers: aemerson, rengolin, llvm-commits
Differential Revision: https://reviews.llvm.org/D28574
llvm-svn: 292409
2017-01-19 01:11:17 +08:00
|
|
|
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
namespace __scudo {
|
|
|
|
|
|
|
|
enum AllocType : u8 {
|
2017-08-28 23:20:02 +08:00
|
|
|
FromMalloc = 0, // Memory block came from malloc, realloc, calloc, etc.
|
|
|
|
FromNew = 1, // Memory block came from operator new.
|
|
|
|
FromNewArray = 2, // Memory block came from operator new [].
|
|
|
|
FromMemalign = 3, // Memory block came from memalign, posix_memalign, etc.
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
};
|
|
|
|
|
2016-10-27 00:16:58 +08:00
|
|
|
enum ChunkState : u8 {
|
|
|
|
ChunkAvailable = 0,
|
|
|
|
ChunkAllocated = 1,
|
|
|
|
ChunkQuarantine = 2
|
|
|
|
};
|
|
|
|
|
[scudo] 32-bit and hardware agnostic support
Summary:
This update introduces i386 support for the Scudo Hardened Allocator, and
offers software alternatives for functions that used to require hardware
specific instruction sets. This should make porting to new architectures
easier.
Among the changes:
- The chunk header has been changed to accomodate the size limitations
encountered on 32-bit architectures. We now fit everything in 64-bit. This
was achieved by storing the amount of unused bytes in an allocation rather
than the size itself, as one can be deduced from the other with the help
of the GetActuallyAllocatedSize function. As it turns out, this header can
be used for both 64 and 32 bit, and as such we dropped the requirement for
the 128-bit compare and exchange instruction support (cmpxchg16b).
- Add 32-bit support for the checksum and the PRNG functions: if the SSE 4.2
instruction set is supported, use the 32-bit CRC32 instruction, and in the
XorShift128, use a 32-bit based state instead of 64-bit.
- Add software support for CRC32: if SSE 4.2 is not supported, fallback on a
software implementation.
- Modify tests that were not 32-bit compliant, and expand them to cover more
allocation and alignment sizes. The random shuffle test has been deactivated
for linux-i386 & linux-i686 as the 32-bit sanitizer allocator doesn't
currently randomize chunks.
Reviewers: alekseyshl, kcc
Subscribers: filcab, llvm-commits, tberghammer, danalbert, srhines, mgorny, modocache
Differential Revision: https://reviews.llvm.org/D26358
llvm-svn: 288255
2016-12-01 01:32:20 +08:00
|
|
|
// Our header requires 64 bits of storage. Having the offset saves us from
|
2016-10-27 00:16:58 +08:00
|
|
|
// using functions such as GetBlockBegin, that is fairly costly. Our first
|
|
|
|
// implementation used the MetaData as well, which offers the advantage of
|
|
|
|
// being stored away from the chunk itself, but accessing it was costly as
|
2017-04-20 23:11:00 +08:00
|
|
|
// well. The header will be atomically loaded and stored.
|
2016-10-27 00:16:58 +08:00
|
|
|
typedef u64 PackedHeader;
|
|
|
|
struct UnpackedHeader {
|
2017-04-21 02:07:17 +08:00
|
|
|
u64 Checksum : 16;
|
2017-08-28 23:20:02 +08:00
|
|
|
u64 SizeOrUnusedBytes : 19; // Size for Primary backed allocations, amount of
|
|
|
|
// unused bytes in the chunk for Secondary ones.
|
2017-04-21 02:07:17 +08:00
|
|
|
u64 FromPrimary : 1;
|
2017-08-28 23:20:02 +08:00
|
|
|
u64 State : 2; // available, allocated, or quarantined
|
|
|
|
u64 AllocType : 2; // malloc, new, new[], or memalign
|
|
|
|
u64 Offset : 16; // Offset from the beginning of the backend
|
|
|
|
// allocation to the beginning of the chunk
|
|
|
|
// itself, in multiples of MinAlignment. See
|
|
|
|
// comment about its maximum value and in init().
|
2017-04-21 02:07:17 +08:00
|
|
|
u64 Salt : 8;
|
2016-10-27 00:16:58 +08:00
|
|
|
};
|
|
|
|
|
2017-01-21 02:32:18 +08:00
|
|
|
typedef atomic_uint64_t AtomicPackedHeader;
|
2016-10-27 00:16:58 +08:00
|
|
|
COMPILER_CHECK(sizeof(UnpackedHeader) == sizeof(PackedHeader));
|
|
|
|
|
|
|
|
// Minimum alignment of 8 bytes for 32-bit, 16 for 64-bit
|
|
|
|
const uptr MinAlignmentLog = FIRST_32_SECOND_64(3, 4);
|
2017-04-28 04:21:16 +08:00
|
|
|
const uptr MaxAlignmentLog = 24; // 16 MB
|
2016-10-27 00:16:58 +08:00
|
|
|
const uptr MinAlignment = 1 << MinAlignmentLog;
|
|
|
|
const uptr MaxAlignment = 1 << MaxAlignmentLog;
|
|
|
|
|
[scudo] 32-bit and hardware agnostic support
Summary:
This update introduces i386 support for the Scudo Hardened Allocator, and
offers software alternatives for functions that used to require hardware
specific instruction sets. This should make porting to new architectures
easier.
Among the changes:
- The chunk header has been changed to accomodate the size limitations
encountered on 32-bit architectures. We now fit everything in 64-bit. This
was achieved by storing the amount of unused bytes in an allocation rather
than the size itself, as one can be deduced from the other with the help
of the GetActuallyAllocatedSize function. As it turns out, this header can
be used for both 64 and 32 bit, and as such we dropped the requirement for
the 128-bit compare and exchange instruction support (cmpxchg16b).
- Add 32-bit support for the checksum and the PRNG functions: if the SSE 4.2
instruction set is supported, use the 32-bit CRC32 instruction, and in the
XorShift128, use a 32-bit based state instead of 64-bit.
- Add software support for CRC32: if SSE 4.2 is not supported, fallback on a
software implementation.
- Modify tests that were not 32-bit compliant, and expand them to cover more
allocation and alignment sizes. The random shuffle test has been deactivated
for linux-i386 & linux-i686 as the 32-bit sanitizer allocator doesn't
currently randomize chunks.
Reviewers: alekseyshl, kcc
Subscribers: filcab, llvm-commits, tberghammer, danalbert, srhines, mgorny, modocache
Differential Revision: https://reviews.llvm.org/D26358
llvm-svn: 288255
2016-12-01 01:32:20 +08:00
|
|
|
const uptr ChunkHeaderSize = sizeof(PackedHeader);
|
|
|
|
const uptr AlignedChunkHeaderSize =
|
|
|
|
(ChunkHeaderSize + MinAlignment - 1) & ~(MinAlignment - 1);
|
|
|
|
|
2017-04-28 04:21:16 +08:00
|
|
|
#if SANITIZER_CAN_USE_ALLOCATOR64
|
|
|
|
const uptr AllocatorSpace = ~0ULL;
|
2017-05-15 22:47:19 +08:00
|
|
|
struct AP64 {
|
2017-04-28 04:21:16 +08:00
|
|
|
static const uptr kSpaceBeg = AllocatorSpace;
|
|
|
|
static const uptr kSpaceSize = AllocatorSize;
|
|
|
|
static const uptr kMetadataSize = 0;
|
|
|
|
typedef __scudo::SizeClassMap SizeClassMap;
|
|
|
|
typedef NoOpMapUnmapCallback MapUnmapCallback;
|
|
|
|
static const uptr kFlags =
|
|
|
|
SizeClassAllocator64FlagMasks::kRandomShuffleChunks;
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
};
|
2017-05-15 22:47:19 +08:00
|
|
|
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
2017-04-28 04:21:16 +08:00
|
|
|
#else
|
|
|
|
// Currently, the 32-bit Sanitizer allocator has not yet benefited from all the
|
|
|
|
// security improvements brought to the 64-bit one. This makes the 32-bit
|
|
|
|
// version of Scudo slightly less toughened.
|
|
|
|
static const uptr NumRegions = SANITIZER_MMAP_RANGE_SIZE >> RegionSizeLog;
|
|
|
|
# if SANITIZER_WORDSIZE == 32
|
|
|
|
typedef FlatByteMap<NumRegions> ByteMap;
|
|
|
|
# elif SANITIZER_WORDSIZE == 64
|
|
|
|
typedef TwoLevelByteMap<(NumRegions >> 12), 1 << 12> ByteMap;
|
|
|
|
# endif // SANITIZER_WORDSIZE
|
2017-05-15 22:47:19 +08:00
|
|
|
struct AP32 {
|
|
|
|
static const uptr kSpaceBeg = 0;
|
|
|
|
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
|
|
|
static const uptr kMetadataSize = 0;
|
|
|
|
typedef __scudo::SizeClassMap SizeClassMap;
|
|
|
|
static const uptr kRegionSizeLog = RegionSizeLog;
|
|
|
|
typedef __scudo::ByteMap ByteMap;
|
|
|
|
typedef NoOpMapUnmapCallback MapUnmapCallback;
|
|
|
|
static const uptr kFlags =
|
2017-08-28 23:20:02 +08:00
|
|
|
SizeClassAllocator32FlagMasks::kRandomShuffleChunks |
|
|
|
|
SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch;
|
2017-05-15 22:47:19 +08:00
|
|
|
};
|
|
|
|
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
2017-04-28 04:21:16 +08:00
|
|
|
#endif // SANITIZER_CAN_USE_ALLOCATOR64
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
|
2017-06-30 00:45:20 +08:00
|
|
|
// __sanitizer::RoundUp has a CHECK that is extraneous for us. Use our own.
|
|
|
|
INLINE uptr RoundUpTo(uptr Size, uptr Boundary) {
|
|
|
|
return (Size + Boundary - 1) & ~(Boundary - 1);
|
|
|
|
}
|
|
|
|
|
2017-04-28 04:21:16 +08:00
|
|
|
#include "scudo_allocator_secondary.h"
|
2017-05-12 05:40:45 +08:00
|
|
|
#include "scudo_allocator_combined.h"
|
2017-04-28 04:21:16 +08:00
|
|
|
|
|
|
|
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
|
|
|
typedef ScudoLargeMmapAllocator SecondaryAllocator;
|
2017-05-12 05:40:45 +08:00
|
|
|
typedef ScudoCombinedAllocator<PrimaryAllocator, AllocatorCache,
|
|
|
|
SecondaryAllocator> ScudoBackendAllocator;
|
2017-04-28 04:21:16 +08:00
|
|
|
|
|
|
|
void initScudo();
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
|
|
|
|
void *scudoMalloc(uptr Size, AllocType Type);
|
|
|
|
void scudoFree(void *Ptr, AllocType Type);
|
|
|
|
void scudoSizedFree(void *Ptr, uptr Size, AllocType Type);
|
|
|
|
void *scudoRealloc(void *Ptr, uptr Size);
|
|
|
|
void *scudoCalloc(uptr NMemB, uptr Size);
|
|
|
|
void *scudoMemalign(uptr Alignment, uptr Size);
|
|
|
|
void *scudoValloc(uptr Size);
|
|
|
|
void *scudoPvalloc(uptr Size);
|
|
|
|
int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size);
|
|
|
|
void *scudoAlignedAlloc(uptr Alignment, uptr Size);
|
|
|
|
uptr scudoMallocUsableSize(void *Ptr);
|
|
|
|
|
[scudo] 32-bit and hardware agnostic support
Summary:
This update introduces i386 support for the Scudo Hardened Allocator, and
offers software alternatives for functions that used to require hardware
specific instruction sets. This should make porting to new architectures
easier.
Among the changes:
- The chunk header has been changed to accomodate the size limitations
encountered on 32-bit architectures. We now fit everything in 64-bit. This
was achieved by storing the amount of unused bytes in an allocation rather
than the size itself, as one can be deduced from the other with the help
of the GetActuallyAllocatedSize function. As it turns out, this header can
be used for both 64 and 32 bit, and as such we dropped the requirement for
the 128-bit compare and exchange instruction support (cmpxchg16b).
- Add 32-bit support for the checksum and the PRNG functions: if the SSE 4.2
instruction set is supported, use the 32-bit CRC32 instruction, and in the
XorShift128, use a 32-bit based state instead of 64-bit.
- Add software support for CRC32: if SSE 4.2 is not supported, fallback on a
software implementation.
- Modify tests that were not 32-bit compliant, and expand them to cover more
allocation and alignment sizes. The random shuffle test has been deactivated
for linux-i386 & linux-i686 as the 32-bit sanitizer allocator doesn't
currently randomize chunks.
Reviewers: alekseyshl, kcc
Subscribers: filcab, llvm-commits, tberghammer, danalbert, srhines, mgorny, modocache
Differential Revision: https://reviews.llvm.org/D26358
llvm-svn: 288255
2016-12-01 01:32:20 +08:00
|
|
|
} // namespace __scudo
|
[sanitizer] Initial implementation of a Hardened Allocator
Summary:
This is an initial implementation of a Hardened Allocator based on Sanitizer Common's CombinedAllocator.
It aims at mitigating heap based vulnerabilities by adding several features to the base allocator, while staying relatively fast.
The following were implemented:
- additional consistency checks on the allocation function parameters and on the heap chunks;
- use of checksum protected chunk header, to detect corruption;
- randomness to the allocator base;
- delayed freelist (quarantine), to mitigate use after free and overall determinism.
Additional mitigations are in the works.
Reviewers: eugenis, aizatsky, pcc, krasin, vitalybuka, glider, dvyukov, kcc
Subscribers: kubabrecka, filcab, llvm-commits
Differential Revision: http://reviews.llvm.org/D20084
llvm-svn: 271968
2016-06-07 09:20:26 +08:00
|
|
|
|
|
|
|
#endif // SCUDO_ALLOCATOR_H_
|