Skip to content

[asan] Implement address sanitizer on AIX: shadow memory #136874

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler-rt/lib/asan/asan_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ const uptr kAllocatorSpace = ~(uptr)0;
# endif // SANITIZER_APPLE

# if defined(__powerpc64__)
# if SANITIZER_AIX
const uptr kAllocatorSize = 1ULL << 38; // 256G.
# else
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
# endif
typedef DefaultSizeClassMap SizeClassMap;
# elif defined(__aarch64__) && SANITIZER_ANDROID
// Android needs to support 39, 42 and 48 bit VMA.
Expand Down
10 changes: 9 additions & 1 deletion compiler-rt/lib/asan/asan_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@
# define ASAN_SHADOW_OFFSET_CONST 0x30000000
# elif SANITIZER_IOS
# define ASAN_SHADOW_OFFSET_DYNAMIC
# elif SANITIZER_AIX
# define ASAN_SHADOW_OFFSET_CONST 0x40000000
# else
# define ASAN_SHADOW_OFFSET_CONST 0x20000000
# endif
Expand All @@ -193,7 +195,11 @@
# elif defined(__aarch64__)
# define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000
# elif defined(__powerpc64__)
# define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000
# if SANITIZER_AIX
# define ASAN_SHADOW_OFFSET_CONST 0x0a01000000000000
# else
# define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000
# endif
# elif defined(__s390x__)
# define ASAN_SHADOW_OFFSET_CONST 0x0010000000000000
# elif SANITIZER_FREEBSD
Expand Down Expand Up @@ -272,6 +278,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.

# if defined(__sparc__) && SANITIZER_WORDSIZE == 64
# include "asan_mapping_sparc64.h"
# elif SANITIZER_WORDSIZE == 64 && SANITIZER_AIX
# include "asan_mapping_aix64.h"
# else
# define MEM_TO_SHADOW(mem) \
(((mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET))
Expand Down
184 changes: 184 additions & 0 deletions compiler-rt/lib/asan/asan_mapping_aix64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
//===-- asan_mapping_aix64.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
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// AIX64-specific definitions for ASan memory mapping.
//===----------------------------------------------------------------------===//
#ifndef ASAN_MAPPING_AIX64_H
#define ASAN_MAPPING_AIX64_H

// https://www.ibm.com/docs/en/aix/7.3?topic=concepts-system-memory-allocation-using-malloc-subsystem
//
// For 64-bit on AIX,
// - Data, heap, bss region is from 0x0000 0001 0000 0000 to
// 0x07ff ffff ffff ffff (1ULL << 59).
// - Shared library regions is from:
// 0x0900 0000 0000 0000 to 0x09ff ffff ffff ffff
// or 0x0800 0000 0000 0000 to 0x08ff ffff ffff ffff ((1ULL << 52) * 2)
// - mmap region is from 0x0a00 0000 0000 0000 to 0x0aff ffff ffff ffff
// (1ULL << 52).
// - Initial stack region is from 0x0f00 0000 0000 0000 to
// 0x0fff ffff ffff ffff (1ULL << 56).
//
// All above ranges are too big. And after verifying on AIX,(these datas are
// from experiments on AIX72, AIX OS may change this layout in future)
// - the biggest heap size is 1ULL << 47.
// - the biggest global variable size is 1ULL << 29. (Which may be put in shared
// library data regions because global variables may be compiled to shared
// libraries.)
// the related address range for shared library data regions is:
// 0x0900 1000 0000 0000 to 0x0900 1001 0000 0000
// or 0x0800 1000 0000 0000 to 0x0800 1001 0000 0000 (when above range is
// used by system libraries.)
// - the biggest mmap size is 1ULL << 46.
// - the biggest stack size is 1ULL << 32.
//
// We don't need so big heap and mmap, calling mmap for shadow memory for such
// big heap and mmap is quite slow on AIX, so to balance runtime and examinable
// memory size, we use 1ULL << 39(512GB) as size for each region except mmap
// region. For mmap region, aix system mmap function may return a big range
// address, we allocate 1ULL << 41(2TB).
//
// So the reasonable user space region size is:
// - Data, heap, bss is from 0x0 to 0x0000 007f ffff ffff
// - Shared library data is from:
// 0x0900 1000 0000 0000 to 0x0900 107f ffff ffff
// or 0x0800 1000 0000 0000 to 0x0800 107f ffff ffff
// - mmap is from 0x0a00 0000 0000 0000 to 0x0a00 01ff ffff ffff
// - Stack is from 0x0fff ff80 0000 0000 to 0x0fff ffff ffff ffff
//
// AIX64 set ASAN_SHADOW_OFFSET_CONST at 0x0a01000000000000 because mmap
// memory starts at 0x0a00000000000000 and shadow memory should be allocated
// there. And we keep 0x0a00000000000000 to 0x0a01000000000000 For user mmap
// usage.

// NOTE: Users are not expected to use `mmap` specifying fixed address which is
// inside the shadow memory ranges.

// Default AIX64 mapping:
// || `[0x0fffff8000000000, 0x0fffffffffffffff]` || HighMem ||
// || `[0x0a80fff000000000, 0x0a80ffffffffffff]` || HighShadow ||
// || `[0x0a41000000000000, 0x0a41003fffffffff]` || MidShadow ||
// || `[0x0a21020000000000, 0x0a21020fffffffff]` || Mid2Shadow ||
// || `[0x0a01020000000000, 0x0a01020fffffffff]` || Mid3Shadow ||
// || `[0x0a01000000000000, 0x0a01000fffffffff]` || LowShadow ||
// || `[0x0a00000000000000, 0x0a0001ffffffffff]` || MidMem ||
// || `[0x0900100000000000, 0x0900107fffffffff]` || Mid2Mem ||
// || `[0x0800100000000000, 0x0800107fffffffff]` || Mid3Mem ||
// || `[0x0000000000000000, 0x0000007fffffffff]` || LowMem ||

#define VMA_BITS 58
#define HIGH_BITS (64 - VMA_BITS)

#define MEM_TO_SHADOW(mem) \
((((mem) << HIGH_BITS) >> (HIGH_BITS + (ASAN_SHADOW_SCALE))) + \
ASAN_SHADOW_OFFSET)

#define SHADOW_TO_MEM(ptr) (__asan::ShadowToMemAIX64(ptr))

#define kLowMemBeg 0ULL
#define kLowMemEnd 0x0000007fffffffffULL

#define kLowShadowBeg ASAN_SHADOW_OFFSET
#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd)

#define kHighMemBeg 0x0fffff8000000000ULL

#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd)

#define kMidMemBeg 0x0a00000000000000ULL
#define kMidMemEnd 0x0a0001ffffffffffULL

#define kMidShadowBeg MEM_TO_SHADOW(kMidMemBeg)
#define kMidShadowEnd MEM_TO_SHADOW(kMidMemEnd)

#define kMid2MemBeg 0x0900100000000000ULL
#define kMid2MemEnd 0x0900107fffffffffULL

#define kMid2ShadowBeg MEM_TO_SHADOW(kMid2MemBeg)
#define kMid2ShadowEnd MEM_TO_SHADOW(kMid2MemEnd)

#define kMid3MemBeg 0x0800100000000000ULL
#define kMid3MemEnd 0x0800107fffffffffULL

#define kMid3ShadowBeg MEM_TO_SHADOW(kMid3MemBeg)
#define kMid3ShadowEnd MEM_TO_SHADOW(kMid3MemEnd)

// AIX does not care about the gaps.
#define kZeroBaseShadowStart 0
#define kZeroBaseMaxShadowStart 0

#define kShadowGapBeg 0
#define kShadowGapEnd 0

#define kShadowGap2Beg 0
#define kShadowGap2End 0

#define kShadowGap3Beg 0
#define kShadowGap3End 0

#define kShadowGap4Beg 0
#define kShadowGap4End 0

namespace __asan {

static inline bool AddrIsInLowMem(uptr a) {
PROFILE_ASAN_MAPPING();
return a <= kLowMemEnd;
}

static inline bool AddrIsInLowShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return a >= kLowShadowBeg && a <= kLowShadowEnd;
}

static inline bool AddrIsInMidMem(uptr a) {
PROFILE_ASAN_MAPPING();
return (a >= kMidMemBeg && a <= kMidMemEnd) ||
(a >= kMid2MemBeg && a <= kMid2MemEnd) ||
(a >= kMid3MemBeg && a <= kMid3MemEnd);
}

static inline bool AddrIsInMidShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return (a >= kMidShadowBeg && a <= kMidShadowEnd) ||
(a >= kMid2ShadowBeg && a <= kMid2ShadowEnd) ||
(a >= kMid3ShadowBeg && a <= kMid3ShadowEnd);
}

static inline bool AddrIsInHighMem(uptr a) {
PROFILE_ASAN_MAPPING();
return kHighMemBeg && a >= kHighMemBeg && a <= kHighMemEnd;
}

static inline bool AddrIsInHighShadow(uptr a) {
PROFILE_ASAN_MAPPING();
return kHighMemBeg && a >= kHighShadowBeg && a <= kHighShadowEnd;
}

static inline bool AddrIsInShadowGap(uptr a) { return false; }

static inline constexpr uptr ShadowToMemAIX64(uptr p) {
PROFILE_ASAN_MAPPING();
p -= ASAN_SHADOW_OFFSET;
p <<= ASAN_SHADOW_SCALE;
if (p >= 0x3ffff8000000000ULL) {
// HighMem
p |= (0x03ULL << VMA_BITS);
} else if (p >= 0x100000000000ULL) {
// MidShadow/Mid2Shadow/Mid2Shadow
p |= (0x02ULL << VMA_BITS);
}
return p;
}

} // namespace __asan

#endif // ASAN_MAPPING_AIX64_H
8 changes: 7 additions & 1 deletion compiler-rt/lib/asan/asan_poisoning.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
// for mapping shadow and zeroing out pages doesn't "just work", so we should
// probably provide higher-level interface for these operations.
// For now, just memset on Windows.
if (value || SANITIZER_WINDOWS == 1 ||
// On AIX, calling ReserveShadowMemoryRange() is not allowed to remap the
// memory, so just memset the memory.
# if SANITIZER_WINDOWS || SANITIZER_AIX
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just extend if (value || SANITIZER_WINDOWS || SANITIZER_AIX ||

REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
# else
if (value ||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else {
Expand All @@ -73,6 +78,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr);
}
}
# endif
#endif // SANITIZER_FUCHSIA
}

Expand Down
42 changes: 39 additions & 3 deletions compiler-rt/lib/asan/asan_rtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,23 @@ static void AsanDie() {
WaitForDebugger(flags()->sleep_before_dying, "before dying");

if (flags()->unmap_shadow_on_exit) {
#if SANITIZER_AIX == 1 && SANITIZER_WORDSIZE == 64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use == 1 like here

UnmapOrDie((void *)kHighShadowBeg, kHighShadowEnd - kHighShadowBeg);
UnmapOrDie((void *)kMidShadowBeg, kMidShadowEnd - kMidShadowBeg);

UnmapOrDie((void *)kMid2ShadowBeg, kMid2ShadowEnd - kMid2ShadowBeg);
UnmapOrDie((void *)kMid3ShadowBeg, kMid3ShadowEnd - kMid3ShadowBeg);

UnmapOrDie((void *)kLowShadowBeg, kLowShadowEnd - kLowShadowBeg);
#else
if (kMidMemBeg) {
UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
UnmapOrDie((void *)kLowShadowBeg, kMidMemBeg - kLowShadowBeg);
UnmapOrDie((void *)kMidMemEnd, kHighShadowEnd - kMidMemEnd);
} else {
if (kHighShadowEnd)
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
UnmapOrDie((void *)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
#endif
}
}

Expand All @@ -85,7 +95,11 @@ bool AsanInited() {
bool replace_intrin_cached;

#if !ASAN_FIXED_MAPPING
# if !(SANITIZER_AIX && __powerpc64__)
uptr kHighMemEnd, kMidMemBeg, kMidMemEnd;
# else
uptr kHighMemEnd;
# endif
#endif

// -------------------------- Misc ---------------- {{{1
Expand Down Expand Up @@ -341,17 +355,29 @@ void PrintAddressSpaceLayout() {
(void*)kHighShadowBeg, (void*)kHighShadowEnd);
}
if (kMidMemBeg) {
// AIX shadowgap is always set to 0 for 64-bit.
#if !SANITIZER_AIX || SANITIZER_WORDSIZE != 64
Printf("|| `[%p, %p]` || ShadowGap3 ||\n",
(void*)kShadowGap3Beg, (void*)kShadowGap3End);
#endif
Printf("|| `[%p, %p]` || MidMem ||\n",
(void*)kMidMemBeg, (void*)kMidMemEnd);
#if !SANITIZER_AIX || SANITIZER_WORDSIZE != 64
Printf("|| `[%p, %p]` || ShadowGap2 ||\n",
(void*)kShadowGap2Beg, (void*)kShadowGap2End);
#endif
Printf("|| `[%p, %p]` || MidShadow ||\n",
(void*)kMidShadowBeg, (void*)kMidShadowEnd);
}
#if SANITIZER_AIX == 1 && SANITIZER_WORDSIZE == 64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove == 1

Printf("|| `[%p, %p]` || Mid2Shadow ||\n", (void *)kMid2ShadowBeg,
(void *)kMid2ShadowEnd);
Printf("|| `[%p, %p]` || Mid3Shadow ||\n", (void *)kMid3ShadowBeg,
(void *)kMid3ShadowEnd);
#else
Printf("|| `[%p, %p]` || ShadowGap ||\n",
(void*)kShadowGapBeg, (void*)kShadowGapEnd);
#endif
if (kLowShadowBeg) {
Printf("|| `[%p, %p]` || LowShadow ||\n",
(void*)kLowShadowBeg, (void*)kLowShadowEnd);
Expand All @@ -371,6 +397,13 @@ void PrintAddressSpaceLayout() {
(void*)MEM_TO_SHADOW(kMidShadowBeg),
(void*)MEM_TO_SHADOW(kMidShadowEnd));
}
// On AIX, for 64-bit, there are totally 3 mid memory regions.
#if SANITIZER_AIX == 1 && SANITIZER_WORDSIZE == 64
Printf(" %p %p", (void *)MEM_TO_SHADOW(kMid2ShadowBeg),
(void *)MEM_TO_SHADOW(kMid2ShadowEnd));
Printf(" %p %p", (void *)MEM_TO_SHADOW(kMid3ShadowBeg),
(void *)MEM_TO_SHADOW(kMid3ShadowEnd));
#endif
Printf("\n");
Printf("redzone=%zu\n", (uptr)flags()->redzone);
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Expand All @@ -386,7 +419,10 @@ void PrintAddressSpaceLayout() {
CHECK(ASAN_SHADOW_SCALE >= 3 && ASAN_SHADOW_SCALE <= 7);
if (kMidMemBeg)
CHECK(kMidShadowBeg > kLowShadowEnd &&
// On AIX 64-bit, we have a highly customized memory layout.
#if !SANITIZER_AIX || SANITIZER_WORDSIZE != 64
kMidMemBeg > kMidShadowEnd &&
#endif
kHighShadowBeg > kMidMemEnd);
}

Expand Down
22 changes: 19 additions & 3 deletions compiler-rt/lib/asan/asan_shadow_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,25 @@ void InitializeShadowMemory() {
ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
// mmap the high shadow.
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
# if SANITIZER_AIX == 1 && SANITIZER_WORDSIZE == 64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all this nesting is hard to read
maybe we need a refactoring to make it more generic

// Fox 64-bit AIX, there is a very customized memory layout, we don't have
// the ability to protect all the shadow gaps. But we need to reserve
// shadow memory for middle memory.
if (kMidShadowBeg)
ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");

if (kMid2ShadowBeg)
ReserveShadowMemoryRange(kMid2ShadowBeg, kMid2ShadowEnd, "mid2 shadow");

if (kMid3ShadowBeg)
ReserveShadowMemoryRange(kMid3ShadowBeg, kMid3ShadowEnd, "mid3 shadow");
# else
if (kShadowGapBeg) {
// protect the gap.
ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
}
# endif
} else if (kMidMemBeg &&
MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
Expand Down
18 changes: 18 additions & 0 deletions compiler-rt/test/asan/TestCases/AIX/aix64_mapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %clang_asan -O0 %s -o %t
// RUN: %env_asan_opts=verbosity=2 %run %t 2>&1 | FileCheck %s
// REQUIRES: powerpc64-target-arch

#include <stdio.h>

int main() {
// CHECK: || `[0xfffff8000000000, 0xfffffffffffffff]` || HighMem ||
// CHECK: || `[0xa80fff000000000, 0xa80ffffffffffff]` || HighShadow ||
// CHECK: || `[0xa00000000000000, 0xa0001ffffffffff]` || MidMem ||
// CHECK: || `[0xa41000000000000, 0xa41003fffffffff]` || MidShadow ||
// CHECK: || `[0xa21020000000000, 0xa21020fffffffff]` || Mid2Shadow ||
// CHECK: || `[0xa01020000000000, 0xa01020fffffffff]` || Mid3Shadow ||
// CHECK: || `[0xa01000000000000, 0xa01000fffffffff]` || LowShadow ||
// CHECK: || `[0x000000000000, 0x007fffffffff]` || LowMem ||

return 0;
}
Loading
Loading