1*76559068SAndroid Build Coastguard Worker //===-- chunk.h -------------------------------------------------*- C++ -*-===//
2*76559068SAndroid Build Coastguard Worker //
3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*76559068SAndroid Build Coastguard Worker //
7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*76559068SAndroid Build Coastguard Worker
9*76559068SAndroid Build Coastguard Worker #ifndef SCUDO_CHUNK_H_
10*76559068SAndroid Build Coastguard Worker #define SCUDO_CHUNK_H_
11*76559068SAndroid Build Coastguard Worker
12*76559068SAndroid Build Coastguard Worker #include "platform.h"
13*76559068SAndroid Build Coastguard Worker
14*76559068SAndroid Build Coastguard Worker #include "atomic_helpers.h"
15*76559068SAndroid Build Coastguard Worker #include "checksum.h"
16*76559068SAndroid Build Coastguard Worker #include "common.h"
17*76559068SAndroid Build Coastguard Worker #include "report.h"
18*76559068SAndroid Build Coastguard Worker
19*76559068SAndroid Build Coastguard Worker namespace scudo {
20*76559068SAndroid Build Coastguard Worker
21*76559068SAndroid Build Coastguard Worker extern Checksum HashAlgorithm;
22*76559068SAndroid Build Coastguard Worker
computeChecksum(u32 Seed,uptr Value,uptr * Array,uptr ArraySize)23*76559068SAndroid Build Coastguard Worker inline u16 computeChecksum(u32 Seed, uptr Value, uptr *Array, uptr ArraySize) {
24*76559068SAndroid Build Coastguard Worker // If the hardware CRC32 feature is defined here, it was enabled everywhere,
25*76559068SAndroid Build Coastguard Worker // as opposed to only for crc32_hw.cpp. This means that other hardware
26*76559068SAndroid Build Coastguard Worker // specific instructions were likely emitted at other places, and as a result
27*76559068SAndroid Build Coastguard Worker // there is no reason to not use it here.
28*76559068SAndroid Build Coastguard Worker #if defined(__CRC32__) || defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32)
29*76559068SAndroid Build Coastguard Worker u32 Crc = static_cast<u32>(CRC32_INTRINSIC(Seed, Value));
30*76559068SAndroid Build Coastguard Worker for (uptr I = 0; I < ArraySize; I++)
31*76559068SAndroid Build Coastguard Worker Crc = static_cast<u32>(CRC32_INTRINSIC(Crc, Array[I]));
32*76559068SAndroid Build Coastguard Worker return static_cast<u16>(Crc ^ (Crc >> 16));
33*76559068SAndroid Build Coastguard Worker #else
34*76559068SAndroid Build Coastguard Worker if (HashAlgorithm == Checksum::HardwareCRC32) {
35*76559068SAndroid Build Coastguard Worker u32 Crc = computeHardwareCRC32(Seed, Value);
36*76559068SAndroid Build Coastguard Worker for (uptr I = 0; I < ArraySize; I++)
37*76559068SAndroid Build Coastguard Worker Crc = computeHardwareCRC32(Crc, Array[I]);
38*76559068SAndroid Build Coastguard Worker return static_cast<u16>(Crc ^ (Crc >> 16));
39*76559068SAndroid Build Coastguard Worker } else {
40*76559068SAndroid Build Coastguard Worker u16 Checksum = computeBSDChecksum(static_cast<u16>(Seed), Value);
41*76559068SAndroid Build Coastguard Worker for (uptr I = 0; I < ArraySize; I++)
42*76559068SAndroid Build Coastguard Worker Checksum = computeBSDChecksum(Checksum, Array[I]);
43*76559068SAndroid Build Coastguard Worker return Checksum;
44*76559068SAndroid Build Coastguard Worker }
45*76559068SAndroid Build Coastguard Worker #endif // defined(__CRC32__) || defined(__SSE4_2__) ||
46*76559068SAndroid Build Coastguard Worker // defined(__ARM_FEATURE_CRC32)
47*76559068SAndroid Build Coastguard Worker }
48*76559068SAndroid Build Coastguard Worker
49*76559068SAndroid Build Coastguard Worker namespace Chunk {
50*76559068SAndroid Build Coastguard Worker
51*76559068SAndroid Build Coastguard Worker // Note that in an ideal world, `State` and `Origin` should be `enum class`, and
52*76559068SAndroid Build Coastguard Worker // the associated `UnpackedHeader` fields of their respective enum class type
53*76559068SAndroid Build Coastguard Worker // but https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 prevents it from
54*76559068SAndroid Build Coastguard Worker // happening, as it will error, complaining the number of bits is not enough.
55*76559068SAndroid Build Coastguard Worker enum Origin : u8 {
56*76559068SAndroid Build Coastguard Worker Malloc = 0,
57*76559068SAndroid Build Coastguard Worker New = 1,
58*76559068SAndroid Build Coastguard Worker NewArray = 2,
59*76559068SAndroid Build Coastguard Worker Memalign = 3,
60*76559068SAndroid Build Coastguard Worker };
61*76559068SAndroid Build Coastguard Worker
62*76559068SAndroid Build Coastguard Worker enum State : u8 { Available = 0, Allocated = 1, Quarantined = 2 };
63*76559068SAndroid Build Coastguard Worker
64*76559068SAndroid Build Coastguard Worker typedef u64 PackedHeader;
65*76559068SAndroid Build Coastguard Worker // Update the 'Mask' constants to reflect changes in this structure.
66*76559068SAndroid Build Coastguard Worker struct UnpackedHeader {
67*76559068SAndroid Build Coastguard Worker uptr ClassId : 8;
68*76559068SAndroid Build Coastguard Worker u8 State : 2;
69*76559068SAndroid Build Coastguard Worker // Origin if State == Allocated, or WasZeroed otherwise.
70*76559068SAndroid Build Coastguard Worker u8 OriginOrWasZeroed : 2;
71*76559068SAndroid Build Coastguard Worker uptr SizeOrUnusedBytes : 20;
72*76559068SAndroid Build Coastguard Worker uptr Offset : 16;
73*76559068SAndroid Build Coastguard Worker uptr Checksum : 16;
74*76559068SAndroid Build Coastguard Worker };
75*76559068SAndroid Build Coastguard Worker typedef atomic_u64 AtomicPackedHeader;
76*76559068SAndroid Build Coastguard Worker static_assert(sizeof(UnpackedHeader) == sizeof(PackedHeader), "");
77*76559068SAndroid Build Coastguard Worker
78*76559068SAndroid Build Coastguard Worker // Those constants are required to silence some -Werror=conversion errors when
79*76559068SAndroid Build Coastguard Worker // assigning values to the related bitfield variables.
80*76559068SAndroid Build Coastguard Worker constexpr uptr ClassIdMask = (1UL << 8) - 1;
81*76559068SAndroid Build Coastguard Worker constexpr u8 StateMask = (1U << 2) - 1;
82*76559068SAndroid Build Coastguard Worker constexpr u8 OriginMask = (1U << 2) - 1;
83*76559068SAndroid Build Coastguard Worker constexpr uptr SizeOrUnusedBytesMask = (1UL << 20) - 1;
84*76559068SAndroid Build Coastguard Worker constexpr uptr OffsetMask = (1UL << 16) - 1;
85*76559068SAndroid Build Coastguard Worker constexpr uptr ChecksumMask = (1UL << 16) - 1;
86*76559068SAndroid Build Coastguard Worker
getHeaderSize()87*76559068SAndroid Build Coastguard Worker constexpr uptr getHeaderSize() {
88*76559068SAndroid Build Coastguard Worker return roundUp(sizeof(PackedHeader), 1U << SCUDO_MIN_ALIGNMENT_LOG);
89*76559068SAndroid Build Coastguard Worker }
90*76559068SAndroid Build Coastguard Worker
getAtomicHeader(void * Ptr)91*76559068SAndroid Build Coastguard Worker inline AtomicPackedHeader *getAtomicHeader(void *Ptr) {
92*76559068SAndroid Build Coastguard Worker return reinterpret_cast<AtomicPackedHeader *>(reinterpret_cast<uptr>(Ptr) -
93*76559068SAndroid Build Coastguard Worker getHeaderSize());
94*76559068SAndroid Build Coastguard Worker }
95*76559068SAndroid Build Coastguard Worker
getConstAtomicHeader(const void * Ptr)96*76559068SAndroid Build Coastguard Worker inline const AtomicPackedHeader *getConstAtomicHeader(const void *Ptr) {
97*76559068SAndroid Build Coastguard Worker return reinterpret_cast<const AtomicPackedHeader *>(
98*76559068SAndroid Build Coastguard Worker reinterpret_cast<uptr>(Ptr) - getHeaderSize());
99*76559068SAndroid Build Coastguard Worker }
100*76559068SAndroid Build Coastguard Worker
101*76559068SAndroid Build Coastguard Worker // We do not need a cryptographically strong hash for the checksum, but a CRC
102*76559068SAndroid Build Coastguard Worker // type function that can alert us in the event a header is invalid or
103*76559068SAndroid Build Coastguard Worker // corrupted. Ideally slightly better than a simple xor of all fields.
computeHeaderChecksum(u32 Cookie,const void * Ptr,UnpackedHeader * Header)104*76559068SAndroid Build Coastguard Worker static inline u16 computeHeaderChecksum(u32 Cookie, const void *Ptr,
105*76559068SAndroid Build Coastguard Worker UnpackedHeader *Header) {
106*76559068SAndroid Build Coastguard Worker UnpackedHeader ZeroChecksumHeader = *Header;
107*76559068SAndroid Build Coastguard Worker ZeroChecksumHeader.Checksum = 0;
108*76559068SAndroid Build Coastguard Worker uptr HeaderHolder[sizeof(UnpackedHeader) / sizeof(uptr)];
109*76559068SAndroid Build Coastguard Worker memcpy(&HeaderHolder, &ZeroChecksumHeader, sizeof(HeaderHolder));
110*76559068SAndroid Build Coastguard Worker return computeChecksum(Cookie, reinterpret_cast<uptr>(Ptr), HeaderHolder,
111*76559068SAndroid Build Coastguard Worker ARRAY_SIZE(HeaderHolder));
112*76559068SAndroid Build Coastguard Worker }
113*76559068SAndroid Build Coastguard Worker
storeHeader(u32 Cookie,void * Ptr,UnpackedHeader * NewUnpackedHeader)114*76559068SAndroid Build Coastguard Worker inline void storeHeader(u32 Cookie, void *Ptr,
115*76559068SAndroid Build Coastguard Worker UnpackedHeader *NewUnpackedHeader) {
116*76559068SAndroid Build Coastguard Worker NewUnpackedHeader->Checksum =
117*76559068SAndroid Build Coastguard Worker computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader);
118*76559068SAndroid Build Coastguard Worker PackedHeader NewPackedHeader = bit_cast<PackedHeader>(*NewUnpackedHeader);
119*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(getAtomicHeader(Ptr), NewPackedHeader);
120*76559068SAndroid Build Coastguard Worker }
121*76559068SAndroid Build Coastguard Worker
loadHeader(u32 Cookie,const void * Ptr,UnpackedHeader * NewUnpackedHeader)122*76559068SAndroid Build Coastguard Worker inline void loadHeader(u32 Cookie, const void *Ptr,
123*76559068SAndroid Build Coastguard Worker UnpackedHeader *NewUnpackedHeader) {
124*76559068SAndroid Build Coastguard Worker PackedHeader NewPackedHeader = atomic_load_relaxed(getConstAtomicHeader(Ptr));
125*76559068SAndroid Build Coastguard Worker *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
126*76559068SAndroid Build Coastguard Worker if (UNLIKELY(NewUnpackedHeader->Checksum !=
127*76559068SAndroid Build Coastguard Worker computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader)))
128*76559068SAndroid Build Coastguard Worker reportHeaderCorruption(const_cast<void *>(Ptr));
129*76559068SAndroid Build Coastguard Worker }
130*76559068SAndroid Build Coastguard Worker
isValid(u32 Cookie,const void * Ptr,UnpackedHeader * NewUnpackedHeader)131*76559068SAndroid Build Coastguard Worker inline bool isValid(u32 Cookie, const void *Ptr,
132*76559068SAndroid Build Coastguard Worker UnpackedHeader *NewUnpackedHeader) {
133*76559068SAndroid Build Coastguard Worker PackedHeader NewPackedHeader = atomic_load_relaxed(getConstAtomicHeader(Ptr));
134*76559068SAndroid Build Coastguard Worker *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
135*76559068SAndroid Build Coastguard Worker return NewUnpackedHeader->Checksum ==
136*76559068SAndroid Build Coastguard Worker computeHeaderChecksum(Cookie, Ptr, NewUnpackedHeader);
137*76559068SAndroid Build Coastguard Worker }
138*76559068SAndroid Build Coastguard Worker
139*76559068SAndroid Build Coastguard Worker } // namespace Chunk
140*76559068SAndroid Build Coastguard Worker
141*76559068SAndroid Build Coastguard Worker } // namespace scudo
142*76559068SAndroid Build Coastguard Worker
143*76559068SAndroid Build Coastguard Worker #endif // SCUDO_CHUNK_H_
144