Skip to content

Commit

Permalink
[scudo] Add Scudo support for Trusty OS
Browse files Browse the repository at this point in the history
trusty.cpp and trusty.h define Trusty implementations of map and other
platform-specific functions. In addition to adding Trusty configurations
in allocator_config.h and size_class_map.h, MapSizeIncrement and
PrimaryEnableRandomOffset are added as configurable options in
allocator_config.h.
Background on Trusty: https://source.android.com/security/trusty

Differential Revision: https://reviews.llvm.org/D103578
  • Loading branch information
Daniel Michael authored and Kostya Kortchinsky committed Jun 8, 2021
1 parent 1a216fb commit 2551053
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 8 deletions.
36 changes: 36 additions & 0 deletions compiler-rt/lib/scudo/standalone/allocator_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ namespace scudo {
// // eg: Ptr = Base + (CompactPtr << Scale).
// typedef u32 PrimaryCompactPtrT;
// static const uptr PrimaryCompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
// // Indicates support for offsetting the start of a region by
// // a random number of pages. Only used with primary64.
// static const bool PrimaryEnableRandomOffset = true;
// // Call map for user memory with at least this size. Only used with
// // primary64.
// static const uptr PrimaryMapSizeIncrement = 1UL << 18;
// // Defines the minimal & maximal release interval that can be set.
// static const s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
// static const s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
Expand All @@ -61,6 +67,8 @@ struct DefaultConfig {
static const uptr PrimaryRegionSizeLog = 32U;
typedef uptr PrimaryCompactPtrT;
static const uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const uptr PrimaryMapSizeIncrement = 1UL << 18;
#else
typedef SizeClassAllocator32<DefaultConfig> Primary;
static const uptr PrimaryRegionSizeLog = 19U;
Expand Down Expand Up @@ -89,6 +97,8 @@ struct AndroidConfig {
static const uptr PrimaryRegionSizeLog = 28U;
typedef u32 PrimaryCompactPtrT;
static const uptr PrimaryCompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
static const bool PrimaryEnableRandomOffset = true;
static const uptr PrimaryMapSizeIncrement = 1UL << 18;
#else
typedef SizeClassAllocator32<AndroidConfig> Primary;
static const uptr PrimaryRegionSizeLog = 18U;
Expand Down Expand Up @@ -118,6 +128,8 @@ struct AndroidSvelteConfig {
static const uptr PrimaryRegionSizeLog = 27U;
typedef u32 PrimaryCompactPtrT;
static const uptr PrimaryCompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
static const bool PrimaryEnableRandomOffset = true;
static const uptr PrimaryMapSizeIncrement = 1UL << 18;
#else
typedef SizeClassAllocator32<AndroidSvelteConfig> Primary;
static const uptr PrimaryRegionSizeLog = 16U;
Expand Down Expand Up @@ -146,6 +158,8 @@ struct FuchsiaConfig {
typedef SizeClassAllocator64<FuchsiaConfig> Primary;
static const uptr PrimaryRegionSizeLog = 30U;
typedef u32 PrimaryCompactPtrT;
static const bool PrimaryEnableRandomOffset = true;
static const uptr PrimaryMapSizeIncrement = 1UL << 18;
static const uptr PrimaryCompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
static const s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
static const s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
Expand All @@ -154,12 +168,34 @@ struct FuchsiaConfig {
template <class A>
using TSDRegistryT = TSDRegistrySharedT<A, 8U, 4U>; // Shared, max 8 TSDs.
};

struct TrustyConfig {
using SizeClassMap = TrustySizeClassMap;
static const bool MaySupportMemoryTagging = false;

typedef SizeClassAllocator64<TrustyConfig> Primary;
// Some apps have 1 page of heap total so small regions are necessary.
static const uptr PrimaryRegionSizeLog = 10U;
typedef u32 PrimaryCompactPtrT;
static const bool PrimaryEnableRandomOffset = false;
// Trusty is extremely memory-constrained so minimally round up map calls.
static const uptr PrimaryMapSizeIncrement = 1UL << 4;
static const uptr PrimaryCompactPtrScale = SCUDO_MIN_ALIGNMENT_LOG;
static const s32 PrimaryMinReleaseToOsIntervalMs = INT32_MIN;
static const s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;

typedef MapAllocatorNoCache SecondaryCache;
template <class A>
using TSDRegistryT = TSDRegistrySharedT<A, 1U, 1U>; // Shared, max 1 TSD.
};
#endif

#if SCUDO_ANDROID
typedef AndroidConfig Config;
#elif SCUDO_FUCHSIA
typedef FuchsiaConfig Config;
#elif SCUDO_TRUSTY
typedef TrustyConfig Config;
#else
typedef DefaultConfig Config;
#endif
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/scudo/standalone/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "fuchsia.h"
#include "linux.h"
#include "trusty.h"

#include <stddef.h>
#include <string.h>
Expand Down
8 changes: 7 additions & 1 deletion compiler-rt/lib/scudo/standalone/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// Transitive includes of stdint.h specify some of the defines checked below.
#include <stdint.h>

#if defined(__linux__)
#if defined(__linux__) && !defined(__TRUSTY__)
#define SCUDO_LINUX 1
#else
#define SCUDO_LINUX 0
Expand All @@ -31,6 +31,12 @@
#define SCUDO_FUCHSIA 0
#endif

#if defined(__TRUSTY__)
#define SCUDO_TRUSTY 1
#else
#define SCUDO_TRUSTY 0
#endif

#if __LP64__
#define SCUDO_WORDSIZE 64U
#else
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/scudo/standalone/primary32.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ template <typename Config> class SizeClassAllocator32 {
if (SCUDO_FUCHSIA)
reportError("SizeClassAllocator32 is not supported on Fuchsia");

if (SCUDO_TRUSTY)
reportError("SizeClassAllocator32 is not supported on Trusty");

PossibleRegions.init();

u32 Seed;
Expand Down
17 changes: 10 additions & 7 deletions compiler-rt/lib/scudo/standalone/primary64.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ namespace scudo {
//
// It starts by reserving NumClasses * 2^RegionSizeLog bytes, equally divided in
// Regions, specific to each size class. Note that the base of that mapping is
// random (based to the platform specific map() capabilities), and that each
// Region actually starts at a random offset from its base.
// random (based to the platform specific map() capabilities). If
// PrimaryEnableRandomOffset is set, each Region actually starts at a random
// offset from its base.
//
// Regions are mapped incrementally on demand to fulfill allocation requests,
// those mappings being split into equally sized Blocks based on the size class
Expand Down Expand Up @@ -70,9 +71,12 @@ template <typename Config> class SizeClassAllocator64 {
const uptr PageSize = getPageSizeCached();
for (uptr I = 0; I < NumClasses; I++) {
RegionInfo *Region = getRegionInfo(I);
// The actual start of a region is offseted by a random number of pages.
Region->RegionBeg =
getRegionBaseByClassId(I) + (getRandomModN(&Seed, 16) + 1) * PageSize;
// The actual start of a region is offset by a random number of pages
// when PrimaryEnableRandomOffset is set.
Region->RegionBeg = getRegionBaseByClassId(I) +
(Config::PrimaryEnableRandomOffset
? ((getRandomModN(&Seed, 16) + 1) * PageSize)
: 0);
Region->RandState = getRandomU32(&Seed);
Region->ReleaseInfo.LastReleaseAtNs = Time;
}
Expand Down Expand Up @@ -267,8 +271,7 @@ template <typename Config> class SizeClassAllocator64 {
static const uptr NumClasses = SizeClassMap::NumClasses;
static const uptr PrimarySize = RegionSize * NumClasses;

// Call map for user memory with at least this size.
static const uptr MapSizeIncrement = 1UL << 18;
static const uptr MapSizeIncrement = Config::PrimaryMapSizeIncrement;
// Fill at most this number of batches from the newly map'd memory.
static const u32 MaxNumBatches = SCUDO_ANDROID ? 4U : 8U;

Expand Down
14 changes: 14 additions & 0 deletions compiler-rt/lib/scudo/standalone/size_class_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,20 @@ struct SvelteSizeClassConfig {

typedef FixedSizeClassMap<SvelteSizeClassConfig> SvelteSizeClassMap;

// Trusty is configured to only have one region containing blocks of size
// 2^7 bytes.
struct TrustySizeClassConfig {
static const uptr NumBits = 1;
static const uptr MinSizeLog = 7;
static const uptr MidSizeLog = 7;
static const uptr MaxSizeLog = 7;
static const u32 MaxNumCachedHint = 8;
static const uptr MaxBytesCachedLog = 10;
static const uptr SizeDelta = 0;
};

typedef FixedSizeClassMap<TrustySizeClassConfig> TrustySizeClassMap;

template <typename SCMap> inline void printMap() {
ScopedString Buffer;
uptr PrevS = 0;
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ struct DeathConfig {
static const scudo::s32 PrimaryMaxReleaseToOsIntervalMs = INT32_MAX;
typedef scudo::uptr PrimaryCompactPtrT;
static const scudo::uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const scudo::uptr PrimaryMapSizeIncrement = 1UL << 18;

typedef scudo::MapAllocatorNoCache SecondaryCache;
template <class A> using TSDRegistryT = scudo::TSDRegistrySharedT<A, 1U, 1U>;
Expand Down
8 changes: 8 additions & 0 deletions compiler-rt/lib/scudo/standalone/tests/primary_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct TestConfig1 {
static const bool MaySupportMemoryTagging = false;
typedef scudo::uptr PrimaryCompactPtrT;
static const scudo::uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const scudo::uptr PrimaryMapSizeIncrement = 1UL << 18;
};

struct TestConfig2 {
Expand All @@ -43,6 +45,8 @@ struct TestConfig2 {
static const bool MaySupportMemoryTagging = false;
typedef scudo::uptr PrimaryCompactPtrT;
static const scudo::uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const scudo::uptr PrimaryMapSizeIncrement = 1UL << 18;
};

struct TestConfig3 {
Expand All @@ -57,6 +61,8 @@ struct TestConfig3 {
static const bool MaySupportMemoryTagging = true;
typedef scudo::uptr PrimaryCompactPtrT;
static const scudo::uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const scudo::uptr PrimaryMapSizeIncrement = 1UL << 18;
};

template <typename BaseConfig, typename SizeClassMapT>
Expand Down Expand Up @@ -145,6 +151,8 @@ struct SmallRegionsConfig {
static const bool MaySupportMemoryTagging = false;
typedef scudo::uptr PrimaryCompactPtrT;
static const scudo::uptr PrimaryCompactPtrScale = 0;
static const bool PrimaryEnableRandomOffset = true;
static const scudo::uptr PrimaryMapSizeIncrement = 1UL << 18;
};

// The 64-bit SizeClassAllocator can be easily OOM'd with small region sizes.
Expand Down
100 changes: 100 additions & 0 deletions compiler-rt/lib/scudo/standalone/trusty.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//===-- trusty.cpp ---------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "platform.h"

#if SCUDO_TRUSTY

#include "common.h"
#include "mutex.h"
#include "string_utils.h"
#include "trusty.h"

#include <errno.h> // for errno
#include <stdio.h> // for printf()
#include <stdlib.h> // for getenv()
#include <sys/auxv.h> // for getauxval()
#include <time.h> // for clock_gettime()
#include <trusty_syscalls.h> // for _trusty_brk()

#define SBRK_ALIGN 32

namespace scudo {

uptr getPageSize() { return getauxval(AT_PAGESZ); }

void NORETURN die() { abort(); }

void *map(UNUSED void *Addr, uptr Size, UNUSED const char *Name, uptr Flags,
UNUSED MapPlatformData *Data) {
// Calling _trusty_brk(0) returns the current program break.
uptr ProgramBreak = reinterpret_cast<uptr>(_trusty_brk(0));
uptr Start;
uptr End;

Start = roundUpTo(ProgramBreak, SBRK_ALIGN);
// Don't actually extend the heap if MAP_NOACCESS flag is set since this is
// the case where Scudo tries to reserve a memory region without mapping
// physical pages.
if (Flags & MAP_NOACCESS)
return reinterpret_cast<void *>(Start);

// Attempt to extend the heap by Size bytes using _trusty_brk.
End = roundUpTo(Start + Size, SBRK_ALIGN);
ProgramBreak =
reinterpret_cast<uptr>(_trusty_brk(reinterpret_cast<void *>(End)));
if (ProgramBreak < End) {
errno = ENOMEM;
dieOnMapUnmapError(Size);
return nullptr;
}
return reinterpret_cast<void *>(Start); // Base of new reserved region.
}

// Unmap is a no-op since Trusty uses sbrk instead of memory mapping.
void unmap(UNUSED void *Addr, UNUSED uptr Size, UNUSED uptr Flags,
UNUSED MapPlatformData *Data) {}

void setMemoryPermission(UNUSED uptr Addr, UNUSED uptr Size, UNUSED uptr Flags,
UNUSED MapPlatformData *Data) {}

void releasePagesToOS(UNUSED uptr BaseAddress, UNUSED uptr Offset,
UNUSED uptr Size, UNUSED MapPlatformData *Data) {}

const char *getEnv(const char *Name) { return getenv(Name); }

// All mutex operations are a no-op since Trusty doesn't currently support
// threads.
bool HybridMutex::tryLock() { return true; }

void HybridMutex::lockSlow() {}

void HybridMutex::unlock() {}

u64 getMonotonicTime() {
timespec TS;
clock_gettime(CLOCK_MONOTONIC, &TS);
return static_cast<u64>(TS.tv_sec) * (1000ULL * 1000 * 1000) +
static_cast<u64>(TS.tv_nsec);
}

u32 getNumberOfCPUs() { return 0; }

u32 getThreadID() { return 0; }

bool getRandom(UNUSED void *Buffer, UNUSED uptr Length, UNUSED bool Blocking) {
return false;
}

void outputRaw(const char *Buffer) { printf("%s", Buffer); }

void setAbortMessage(UNUSED const char *Message) {}

} // namespace scudo

#endif // SCUDO_TRUSTY
24 changes: 24 additions & 0 deletions compiler-rt/lib/scudo/standalone/trusty.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===-- trusty.h -----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef SCUDO_TRUSTY_H_
#define SCUDO_TRUSTY_H_

#include "platform.h"

#if SCUDO_TRUSTY

namespace scudo {
// MapPlatformData is unused on Trusty, define it as a minimially sized
// structure.
struct MapPlatformData {};
} // namespace scudo

#endif // SCUDO_TRUSTY

#endif // SCUDO_TRUSTY_H_

0 comments on commit 2551053

Please sign in to comment.