[scudo] Add Scudo support for Trusty OS

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
This commit is contained in:
Daniel Michael 2021-06-07 09:10:46 -07:00 committed by Kostya Kortchinsky
parent 1a216fb15a
commit 2551053e8d
10 changed files with 205 additions and 8 deletions

View File

@ -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;
@ -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;
@ -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;
@ -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;
@ -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;
@ -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

View File

@ -13,6 +13,7 @@
#include "fuchsia.h"
#include "linux.h"
#include "trusty.h"
#include <stddef.h>
#include <string.h>

View File

@ -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
@ -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

View File

@ -64,6 +64,9 @@ public:
if (SCUDO_FUCHSIA)
reportError("SizeClassAllocator32 is not supported on Fuchsia");
if (SCUDO_TRUSTY)
reportError("SizeClassAllocator32 is not supported on Trusty");
PossibleRegions.init();
u32 Seed;

View File

@ -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
@ -70,9 +71,12 @@ public:
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;
}
@ -267,8 +271,7 @@ private:
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;

View File

@ -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;

View File

@ -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>;

View File

@ -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 {
@ -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 {
@ -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>
@ -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.

View File

@ -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

View File

@ -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_