Skip to content

Commit d19dfde

Browse files
[WIP][ASan] Interceptors for WASI
1 parent 51fbd66 commit d19dfde

24 files changed

+7327
-20
lines changed

compiler-rt/lib/asan/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ set(ASAN_SOURCES
2929
asan_stats.cpp
3030
asan_suppressions.cpp
3131
asan_thread.cpp
32+
asan_wasi.cpp
3233
asan_win.cpp
34+
wasi/memset.c
35+
wasi/memcpy.c
3336
)
3437

3538
if (NOT WIN32 AND NOT APPLE)

compiler-rt/lib/asan/asan_interceptors.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
#include "sanitizer_common/sanitizer_internal_defs.h"
2828
#include "sanitizer_common/sanitizer_libc.h"
2929

30-
// There is no general interception at all on Fuchsia.
30+
// There is no general interception at all on Fuchsia and WASI.
3131
// Only the functions in asan_interceptors_memintrinsics.cpp are
3232
// really defined to replace libc functions.
33-
#if !SANITIZER_FUCHSIA
33+
#if !SANITIZER_FUCHSIA && !SANITIZER_WASI
3434

3535
# if SANITIZER_POSIX
3636
# include "sanitizer_common/sanitizer_posix.h"

compiler-rt/lib/asan/asan_interceptors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void InitializePlatformInterceptors();
3333

3434
// Use macro to describe if specific function should be
3535
// intercepted on a given platform.
36-
#if !SANITIZER_WINDOWS
36+
#if !SANITIZER_WINDOWS && !SANITIZER_WASI
3737
# define ASAN_INTERCEPT__LONGJMP 1
3838
# define ASAN_INTERCEPT_INDEX 1
3939
# define ASAN_INTERCEPT_PTHREAD_CREATE 1

compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) {
7171
ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
7272
}
7373

74-
#if SANITIZER_FUCHSIA
74+
#if SANITIZER_FUCHSIA || SANITIZER_WASI
7575

7676
// Fuchsia doesn't use sanitizer_common_interceptors.inc, but
7777
// the only things there it wants are these three. Just define them

compiler-rt/lib/asan/asan_malloc_linux.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#include "sanitizer_common/sanitizer_platform.h"
1717
#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
18-
SANITIZER_NETBSD || SANITIZER_SOLARIS
18+
SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_WASI
1919

2020
# include "asan_allocator.h"
2121
# include "asan_interceptors.h"
@@ -83,6 +83,12 @@ INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
8383
return asan_realloc(ptr, size, &stack);
8484
}
8585

86+
#if SANITIZER_WASI
87+
extern "C" void *__libc_malloc(uptr) __attribute__((alias("malloc")));
88+
extern "C" void __libc_free(void *) __attribute__((alias("free")));
89+
extern "C" void *__libc_calloc(uptr nmemb, uptr size) __attribute__((alias("calloc")));
90+
#endif
91+
8692
#if SANITIZER_INTERCEPT_REALLOCARRAY
8793
INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) {
8894
AsanInitFromRtl();

compiler-rt/lib/asan/asan_mapping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init.
272272

273273
# if defined(__sparc__) && SANITIZER_WORDSIZE == 64
274274
# include "asan_mapping_sparc64.h"
275+
# elif SANITIZER_WASI
276+
# include "asan_mapping_wasi.h"
275277
# else
276278
# define MEM_TO_SHADOW(mem) \
277279
(((mem) >> ASAN_SHADOW_SCALE) + (ASAN_SHADOW_OFFSET))
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===-- asan_mapping_wasi.h ----------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// WASI-specific definitions for ASan memory mapping.
10+
//===----------------------------------------------------------------------===//
11+
12+
#ifndef ASAN_MAPPING_WASI_H
13+
#define ASAN_MAPPING_WASI_H
14+
15+
extern char __global_base;
16+
17+
#define kLowMemBeg ((uptr) &__global_base)
18+
#define kLowMemEnd ((kLowShadowBeg << ASAN_SHADOW_SCALE) - 1)
19+
20+
#define kLowShadowBeg 0
21+
#define kLowShadowEnd ((uptr) &__global_base - 1)
22+
23+
#define kHighMemBeg 0
24+
25+
#define kHighShadowBeg 0
26+
#define kHighShadowEnd 0
27+
28+
#define kMidShadowBeg 0
29+
#define kMidShadowEnd 0
30+
31+
#define kShadowGapBeg (kLowMemEnd + 1)
32+
#define kShadowGapEnd 0xFFFFFFFF
33+
34+
#define kShadowGap2Beg 0
35+
#define kShadowGap2End 0
36+
37+
#define kShadowGap3Beg 0
38+
#define kShadowGap3End 0
39+
40+
// The first 1/8 of the shadow memory space is shadowing itself.
41+
// This allows attempted accesses into the shadow memory, as well as null
42+
// pointer dereferences, to be detected properly.
43+
// The shadow memory of the shadow memory is poisoned.
44+
#define MEM_TO_SHADOW(mem) ((mem) >> ASAN_SHADOW_SCALE)
45+
#define SHADOW_TO_MEM(mem) ((mem) << ASAN_SHADOW_SCALE)
46+
47+
namespace __asan {
48+
49+
static inline bool AddrIsInLowMem(uptr a) {
50+
PROFILE_ASAN_MAPPING();
51+
return a >= kLowMemBeg && a <= kLowMemEnd;
52+
}
53+
54+
static inline bool AddrIsInLowShadow(uptr a) {
55+
PROFILE_ASAN_MAPPING();
56+
return a >= kLowShadowBeg && a <= kLowShadowEnd;
57+
}
58+
59+
static inline bool AddrIsInMidMem(uptr a) {
60+
PROFILE_ASAN_MAPPING();
61+
return false;
62+
}
63+
64+
static inline bool AddrIsInMidShadow(uptr a) {
65+
PROFILE_ASAN_MAPPING();
66+
return false;
67+
}
68+
69+
static inline bool AddrIsInHighMem(uptr a) {
70+
PROFILE_ASAN_MAPPING();
71+
return false;
72+
}
73+
74+
static inline bool AddrIsInHighShadow(uptr a) {
75+
PROFILE_ASAN_MAPPING();
76+
return false;
77+
}
78+
79+
static inline bool AddrIsInShadowGap(uptr a) {
80+
PROFILE_ASAN_MAPPING();
81+
return a >= kShadowGapBeg;
82+
}
83+
84+
} // namespace __asan
85+
86+
#endif // ASAN_MAPPING_WASI_H

compiler-rt/lib/asan/asan_poisoning.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
5151
// probably provide higher-level interface for these operations.
5252
// For now, just memset on Windows.
5353
if (value || SANITIZER_WINDOWS == 1 ||
54+
SANITIZER_WASI == 1 ||
5455
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
5556
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
5657
} else {

compiler-rt/lib/asan/asan_shadow_setup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include "sanitizer_common/sanitizer_platform.h"
1515

1616
// asan_fuchsia.cpp has their own InitializeShadowMemory implementation.
17-
#if !SANITIZER_FUCHSIA
17+
#if !SANITIZER_FUCHSIA && !SANITIZER_WASI
1818

1919
# include "asan_internal.h"
2020
# include "asan_mapping.h"

compiler-rt/lib/asan/asan_wasi.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===-- asan_wasi.cpp -----------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// WASI-specific details.
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "sanitizer_common/sanitizer_platform.h"
15+
#include "sanitizer_common/sanitizer_internal_defs.h"
16+
17+
#if SANITIZER_WASI
18+
19+
#include "asan/asan_poisoning.h"
20+
#include "asan_interceptors.h"
21+
#include "asan_internal.h"
22+
23+
namespace __asan {
24+
25+
void InitializeShadowMemory() {
26+
// Poison the shadow memory itself to catch invalid shadow accesses and
27+
// also to catch null pointer dereferences.
28+
FastPoisonShadow(kLowShadowBeg, kLowShadowEnd - kLowShadowBeg, kAsanGlobalRedzoneMagic);
29+
}
30+
31+
void InitializePlatformInterceptors() {}
32+
void InitializePlatformExceptionHandlers() {}
33+
34+
void AsanCheckDynamicRTPrereqs() {}
35+
void AsanCheckIncompatibleRT() {}
36+
void InitializeAsanInterceptors() {}
37+
38+
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
39+
UNIMPLEMENTED();
40+
}
41+
42+
bool PlatformUnpoisonStacks() { return false; }
43+
44+
// Simple thread local storage implementation for WASI
45+
static thread_local void *per_thread;
46+
47+
void *AsanTSDGet() { return per_thread; }
48+
49+
void AsanTSDSet(void *tsd) { per_thread = tsd; }
50+
51+
void AsanTSDInit(void (*destructor)(void *tsd)) {
52+
DCHECK(destructor == &PlatformTSDDtor);
53+
}
54+
55+
void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
56+
57+
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
58+
UNIMPLEMENTED();
59+
}
60+
61+
void InstallAtForkHandler() {
62+
// WASI doesn't support fork
63+
}
64+
65+
void FlushUnneededASanShadowMemory(uptr p, uptr size) {
66+
// No-op as madvise is not supported on WASI
67+
}
68+
69+
// On WASI, leak detection is not supported yet
70+
void InstallAtExitCheckLeaks() {}
71+
72+
// On WASI Preview 1, dlopen is not supported
73+
bool HandleDlopenInit() { return false; }
74+
75+
// WASI does not support ASLR
76+
void TryReExecWithoutASLR() {}
77+
78+
} // namespace __asan
79+
80+
#endif // SANITIZER_WASI

compiler-rt/lib/asan/wasi/dlmalloc.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// This file is a wrapper around malloc.c, which is the upstream source file.
2+
// It sets configuration flags and controls which symbols are exported.
3+
4+
#include <stddef.h>
5+
#include <malloc.h>
6+
7+
// Define configuration macros for dlmalloc.
8+
9+
// WebAssembly doesn't have mmap-style memory allocation.
10+
#define HAVE_MMAP 0
11+
12+
// WebAssembly doesn't support shrinking linear memory.
13+
#define MORECORE_CANNOT_TRIM 1
14+
15+
// Disable sanity checks to reduce code size.
16+
#define ABORT __builtin_unreachable()
17+
18+
// If threads are enabled, enable support for threads.
19+
#ifdef _REENTRANT
20+
#define USE_LOCKS 1
21+
#endif
22+
23+
// Make malloc deterministic.
24+
#define LACKS_TIME_H 1
25+
26+
// Disable malloc statistics generation to reduce code size.
27+
#define NO_MALLINFO 1
28+
#define NO_MALLOC_STATS 1
29+
30+
// Align malloc regions to 16, to avoid unaligned SIMD accesses.
31+
#define MALLOC_ALIGNMENT 16
32+
33+
// Declare errno values used by dlmalloc. We define them like this to avoid
34+
// putting specific errno values in the ABI.
35+
extern const int __ENOMEM;
36+
#define ENOMEM __ENOMEM
37+
extern const int __EINVAL;
38+
#define EINVAL __EINVAL
39+
40+
// Define USE_DL_PREFIX so that we leave dlmalloc's names prefixed with 'dl'.
41+
// We define them as "static", and we wrap them with public names below. This
42+
// serves two purposes:
43+
//
44+
// One is to make it easy to control which symbols are exported; dlmalloc
45+
// defines several non-standard functions and we wish to explicitly control
46+
// which functions are part of our public-facing interface.
47+
//
48+
// The other is to protect against compilers optimizing based on the assumption
49+
// that they know what functions with names like "malloc" do. Code in the
50+
// implementation will call functions like "dlmalloc" and assume it can use
51+
// the resulting pointers to access the metadata outside of the nominally
52+
// allocated objects. However, if the function were named "malloc", compilers
53+
// might see code like that and assume it has undefined behavior and can be
54+
// optimized away. By using "dlmalloc" in the implementation, we don't need
55+
// -fno-builtin to avoid this problem.
56+
#define USE_DL_PREFIX 1
57+
#define DLMALLOC_EXPORT extern "C"
58+
59+
// This isn't declared with DLMALLOC_EXPORT so make it static explicitly.
60+
static size_t dlmalloc_usable_size(void*);
61+
62+
// Include the upstream dlmalloc's malloc.c.
63+
#include "malloc.c"
64+
65+
// Export the public names.
66+
67+
#if 0
68+
void *malloc(size_t size) {
69+
return dlmalloc(size);
70+
}
71+
72+
void free(void *ptr) {
73+
dlfree(ptr);
74+
}
75+
76+
void *calloc(size_t nmemb, size_t size) {
77+
return dlcalloc(nmemb, size);
78+
}
79+
80+
void *realloc(void *ptr, size_t size) {
81+
return dlrealloc(ptr, size);
82+
}
83+
84+
int posix_memalign(void **memptr, size_t alignment, size_t size) {
85+
return dlposix_memalign(memptr, alignment, size);
86+
}
87+
88+
void* aligned_alloc(size_t alignment, size_t bytes) {
89+
return dlmemalign(alignment, bytes);
90+
}
91+
92+
size_t malloc_usable_size(void *ptr) {
93+
return dlmalloc_usable_size(ptr);
94+
}
95+
96+
// Define these to satisfy musl references.
97+
void *__libc_malloc(size_t) __attribute__((alias("malloc")));
98+
void __libc_free(void *) __attribute__((alias("free")));
99+
void *__libc_calloc(size_t nmemb, size_t size) __attribute__((alias("calloc")));
100+
101+
#endif

0 commit comments

Comments
 (0)