Skip to content

Commit 5f58322

Browse files
committed
[HWASan] Build separate LAM runtime on x86_64.
Since we have both aliasing mode and Intel LAM on x86_64, we need to choose the mode at either run time or compile time. This patch implements the plumbing to build both and choose between them at compile time. Reviewed By: vitalybuka, eugenis Differential Revision: https://reviews.llvm.org/D102286
1 parent af6511d commit 5f58322

File tree

6 files changed

+118
-43
lines changed

6 files changed

+118
-43
lines changed

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -816,8 +816,12 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
816816
}
817817
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
818818
SharedRuntimes.push_back("tsan");
819-
if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes())
820-
SharedRuntimes.push_back("hwasan");
819+
if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
820+
if (SanArgs.needsHwasanAliasesRt())
821+
SharedRuntimes.push_back("hwasan_aliases");
822+
else
823+
SharedRuntimes.push_back("hwasan");
824+
}
821825
}
822826

823827
// The stats_client library is also statically linked into DSOs.
@@ -847,9 +851,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
847851
}
848852

849853
if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
850-
StaticRuntimes.push_back("hwasan");
851-
if (SanArgs.linkCXXRuntimes())
852-
StaticRuntimes.push_back("hwasan_cxx");
854+
if (SanArgs.needsHwasanAliasesRt()) {
855+
StaticRuntimes.push_back("hwasan_aliases");
856+
if (SanArgs.linkCXXRuntimes())
857+
StaticRuntimes.push_back("hwasan_aliases_cxx");
858+
} else {
859+
StaticRuntimes.push_back("hwasan");
860+
if (SanArgs.linkCXXRuntimes())
861+
StaticRuntimes.push_back("hwasan_cxx");
862+
}
853863
}
854864
if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes())
855865
StaticRuntimes.push_back("dfsan");

compiler-rt/lib/hwasan/CMakeLists.txt

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,54 +93,86 @@ add_compiler_rt_object_libraries(RTHwasan_dynamic
9393
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
9494
DEFS ${HWASAN_DEFINITIONS})
9595

96+
# Compile a different runtime for x86 aliasing mode.
97+
set(HWASAN_ALIASES_RTL_CFLAGS ${HWASAN_RTL_CFLAGS})
98+
list(APPEND HWASAN_ALIASES_RTL_CFLAGS -DHWASAN_ALIASING_MODE)
99+
set(HWASAN_ALIASES_DYNAMIC_CFLAGS ${HWASAN_DYNAMIC_CFLAGS})
100+
list(APPEND HWASAN_ALIASES_DYNAMIC_CFLAGS -DHWASAN_ALIASING_MODE)
101+
add_compiler_rt_object_libraries(RTHwasanAliases
102+
ARCHS ${HWASAN_SUPPORTED_ARCH}
103+
SOURCES ${HWASAN_RTL_SOURCES}
104+
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
105+
CFLAGS ${HWASAN_ALIASES_RTL_CFLAGS}
106+
DEFS ${HWASAN_DEFINITIONS})
107+
add_compiler_rt_object_libraries(RTHwasanAliases_dynamic
108+
ARCHS ${HWASAN_SUPPORTED_ARCH}
109+
SOURCES ${HWASAN_RTL_SOURCES} ${HWASAN_RTL_CXX_SOURCES}
110+
ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
111+
CFLAGS ${HWASAN_ALIASES_DYNAMIC_CFLAGS}
112+
DEFS ${HWASAN_DEFINITIONS})
113+
96114
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "")
97115
add_compiler_rt_object_libraries(RTHwasan_dynamic_version_script_dummy
98116
ARCHS ${HWASAN_SUPPORTED_ARCH}
99117
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
100118
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
101119
DEFS ${HWASAN_DEFINITIONS})
102120

103-
foreach(arch ${HWASAN_SUPPORTED_ARCH})
104-
add_compiler_rt_runtime(clang_rt.hwasan
121+
# If use_aliases is TRUE, adds the HWASan runtime built with alias support.
122+
# Otherwise adds the runtime without alias support.
123+
function(add_hwasan_runtimes arch use_aliases)
124+
set(hwasan_object_lib RTHwasan)
125+
set(hwasan_object_dyn_lib RTHwasan_dynamic)
126+
set(hwasan_runtime clang_rt.hwasan)
127+
set(hwasan_rtl_flags ${HWASAN_RTL_CFLAGS})
128+
set(hwasan_dyn_flags ${HWASAN_DYNAMIC_CFLAGS})
129+
if(use_aliases)
130+
set(hwasan_object_lib RTHwasanAliases)
131+
set(hwasan_object_dyn_lib RTHwasanAliases_dynamic)
132+
set(hwasan_runtime clang_rt.hwasan_aliases)
133+
set(hwasan_rtl_flags ${HWASAN_ALIASES_RTL_CFLAGS})
134+
set(hwasan_dyn_flags ${HWASAN_ALIASES_DYNAMIC_CFLAGS})
135+
endif()
136+
add_compiler_rt_runtime(${hwasan_runtime}
105137
STATIC
106138
ARCHS ${arch}
107-
OBJECT_LIBS RTHwasan
139+
OBJECT_LIBS ${hwasan_object_lib}
108140
RTInterception
109141
RTSanitizerCommon
110142
RTSanitizerCommonLibc
111143
RTSanitizerCommonCoverage
112144
RTSanitizerCommonSymbolizer
113145
RTUbsan
114-
CFLAGS ${HWASAN_RTL_CFLAGS}
146+
CFLAGS ${hwasan_rtl_flags}
115147
PARENT_TARGET hwasan)
116-
add_compiler_rt_runtime(clang_rt.hwasan_cxx
148+
add_compiler_rt_runtime(${hwasan_runtime}_cxx
117149
STATIC
118150
ARCHS ${arch}
119151
OBJECT_LIBS RTHwasan_cxx
120152
RTUbsan_cxx
121-
CFLAGS ${HWASAN_RTL_CFLAGS}
153+
CFLAGS ${hwasan_rtl_flags}
122154
PARENT_TARGET hwasan)
123155

124156
if (UNIX)
125-
add_sanitizer_rt_version_list(clang_rt.hwasan-dynamic-${arch}
126-
LIBS clang_rt.hwasan-${arch} clang_rt.hwasan_cxx-${arch}
157+
add_sanitizer_rt_version_list(${hwasan_runtime}-dynamic-${arch}
158+
LIBS ${hwasan_runtime}-${arch} ${hwasan_runtime}_cxx-${arch}
127159
EXTRA hwasan.syms.extra)
128160
set(VERSION_SCRIPT_FLAG
129-
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.hwasan-dynamic-${arch}.vers)
161+
-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/${hwasan_runtime}-dynamic-${arch}.vers)
130162
set_property(SOURCE
131163
${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp
132164
APPEND PROPERTY
133-
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clang_rt.hwasan-dynamic-${arch}.vers)
165+
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${hwasan_runtime}-dynamic-${arch}.vers)
134166
else()
135167
set(VERSION_SCRIPT_FLAG)
136168
endif()
137169

138170

139-
add_compiler_rt_runtime(clang_rt.hwasan
171+
add_compiler_rt_runtime(${hwasan_runtime}
140172
SHARED
141173
ARCHS ${arch}
142174
OBJECT_LIBS
143-
RTHwasan_dynamic
175+
${hwasan_object_dyn_lib}
144176
RTInterception
145177
RTSanitizerCommon
146178
RTSanitizerCommonLibc
@@ -154,22 +186,29 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})
154186
# add_dependencies(clang_rt.asan-dynamic-${arch} clang_rt.asan-dynamic-${arch}-version-list)
155187
# generates an order-only dependency in ninja.
156188
RTHwasan_dynamic_version_script_dummy
157-
CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
189+
CFLAGS ${hwasan_dyn_flags}
158190
LINK_FLAGS ${HWASAN_DYNAMIC_LINK_FLAGS}
159191
${VERSION_SCRIPT_FLAG}
160192
LINK_LIBS ${HWASAN_DYNAMIC_LIBS}
161193
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
162194
PARENT_TARGET hwasan)
163195

164196
if(SANITIZER_USE_SYMBOLS)
165-
add_sanitizer_rt_symbols(clang_rt.hwasan
197+
add_sanitizer_rt_symbols(${hwasan_runtime}
166198
ARCHS ${arch}
167199
EXTRA hwasan.syms.extra)
168-
add_sanitizer_rt_symbols(clang_rt.hwasan_cxx
200+
add_sanitizer_rt_symbols(${hwasan_runtime}_cxx
169201
ARCHS ${arch}
170202
EXTRA hwasan.syms.extra)
171-
add_dependencies(hwasan clang_rt.hwasan-${arch}-symbols
172-
clang_rt.hwasan_cxx-${arch}-symbols)
203+
add_dependencies(hwasan ${hwasan_runtime}-${arch}-symbols
204+
${hwasan_runtime}_cxx-${arch}-symbols)
205+
endif()
206+
endfunction()
207+
208+
foreach(arch ${HWASAN_SUPPORTED_ARCH})
209+
add_hwasan_runtimes(${arch} FALSE)
210+
if(${arch} MATCHES "x86_64")
211+
add_hwasan_runtimes(${arch} TRUE)
173212
endif()
174213
endforeach()
175214

compiler-rt/lib/hwasan/hwasan.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636

3737
typedef u8 tag_t;
3838

39-
#if defined(__x86_64__)
39+
#if defined(HWASAN_ALIASING_MODE)
40+
# if !defined(__x86_64__)
41+
# error Aliasing mode is only supported on x86_64
42+
# endif
4043
// Tags are done in middle bits using userspace aliasing.
4144
constexpr unsigned kAddressTagShift = 39;
4245
constexpr unsigned kTagBits = 3;
@@ -49,12 +52,16 @@ constexpr unsigned kTagBits = 3;
4952
// simpler/faster shadow calculation.
5053
constexpr unsigned kTaggableRegionCheckShift =
5154
__sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
55+
#elif defined(__x86_64__)
56+
// Tags are done in upper bits using Intel LAM.
57+
constexpr unsigned kAddressTagShift = 57;
58+
constexpr unsigned kTagBits = 6;
5259
#else
5360
// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
5461
// translation and can be used to store a tag.
5562
constexpr unsigned kAddressTagShift = 56;
5663
constexpr unsigned kTagBits = 8;
57-
#endif // defined(__x86_64__)
64+
#endif // defined(HWASAN_ALIASING_MODE)
5865

5966
// Mask for extracting tag bits from the lower 8 bits.
6067
constexpr uptr kTagMask = (1UL << kTagBits) - 1;

compiler-rt/lib/hwasan/hwasan_allocator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T
5858
struct AP64 {
5959
static const uptr kSpaceBeg = ~0ULL;
6060

61-
#if defined(__x86_64__)
61+
#if defined(HWASAN_ALIASING_MODE)
6262
static const uptr kSpaceSize = 1ULL << kAddressTagShift;
6363
#else
6464
static const uptr kSpaceSize = 0x2000000000ULL;
@@ -110,7 +110,7 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
110110
void GetAllocatorStats(AllocatorStatCounters s);
111111

112112
inline bool InTaggableRegion(uptr addr) {
113-
#if defined(__x86_64__)
113+
#if defined(HWASAN_ALIASING_MODE)
114114
// Aliases are mapped next to shadow so that the upper bits match the shadow
115115
// base.
116116
return (addr >> kTaggableRegionCheckShift) ==

compiler-rt/lib/hwasan/hwasan_dynamic_shadow.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ namespace __hwasan {
119119
void InitShadowGOT() {}
120120

121121
uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
122-
#if defined(__x86_64__)
122+
# if defined(HWASAN_ALIASING_MODE)
123123
constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
124124
constexpr uptr kNumAliases = 1ULL << kTagBits;
125125
return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
126126
RingBufferSize());
127-
#endif
127+
# endif
128128
return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
129129
kHighMemEnd);
130130
}

compiler-rt/lib/hwasan/hwasan_linux.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ uptr kHighShadowEnd;
7676
uptr kHighMemStart;
7777
uptr kHighMemEnd;
7878

79-
uptr kAliasRegionStart; // Always 0 on non-x86.
79+
uptr kAliasRegionStart; // Always 0 when aliases aren't used.
8080

8181
static void PrintRange(uptr start, uptr end, const char *name) {
8282
Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
@@ -125,33 +125,50 @@ void InitPrctl() {
125125
if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
126126
&local_errno) &&
127127
local_errno == EINVAL) {
128-
#if SANITIZER_ANDROID || defined(__x86_64__)
128+
# if SANITIZER_ANDROID || defined(HWASAN_ALIASING_MODE)
129129
// Some older Android kernels have the tagged pointer ABI on
130130
// unconditionally, and hence don't have the tagged-addr prctl while still
131131
// allow the ABI.
132132
// If targeting Android and the prctl is not around we assume this is the
133133
// case.
134134
return;
135-
#else
135+
# else
136136
if (flags()->fail_without_syscall_abi) {
137137
Printf(
138138
"FATAL: "
139139
"HWAddressSanitizer requires a kernel with tagged address ABI.\n");
140140
Die();
141141
}
142-
#endif
142+
# endif
143143
}
144144

145145
// Turn on the tagged address ABI.
146146
if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
147147
PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
148-
!internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
149-
flags()->fail_without_syscall_abi) {
150-
Printf(
151-
"FATAL: HWAddressSanitizer failed to enable tagged address syscall "
152-
"ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
153-
"configuration.\n");
154-
Die();
148+
!internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0))) {
149+
# if defined(__x86_64__) && !defined(HWASAN_ALIASING_MODE)
150+
// Try the new prctl API for Intel LAM. The API is based on a currently
151+
// unsubmitted patch to the Linux kernel (as of May 2021) and is thus
152+
// subject to change. Patch is here:
153+
// https://lore.kernel.org/linux-mm/[email protected]/
154+
int tag_bits = kTagBits;
155+
int tag_shift = kAddressTagShift;
156+
if (!internal_iserror(
157+
internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE,
158+
reinterpret_cast<unsigned long>(&tag_bits),
159+
reinterpret_cast<unsigned long>(&tag_shift), 0))) {
160+
CHECK_EQ(tag_bits, kTagBits);
161+
CHECK_EQ(tag_shift, kAddressTagShift);
162+
return;
163+
}
164+
# endif // defined(__x86_64__) && !defined(HWASAN_ALIASING_MODE)
165+
if (flags()->fail_without_syscall_abi) {
166+
Printf(
167+
"FATAL: HWAddressSanitizer failed to enable tagged address syscall "
168+
"ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
169+
"configuration.\n");
170+
Die();
171+
}
155172
}
156173
#undef PR_SET_TAGGED_ADDR_CTRL
157174
#undef PR_GET_TAGGED_ADDR_CTRL
@@ -181,7 +198,7 @@ bool InitShadow() {
181198
// High memory starts where allocated shadow allows.
182199
kHighMemStart = ShadowToMem(kHighShadowStart);
183200

184-
#if defined(__x86_64__)
201+
# if defined(HWASAN_ALIASING_MODE)
185202
constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
186203
kAliasRegionStart =
187204
__hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
@@ -191,7 +208,7 @@ bool InitShadow() {
191208
CHECK_EQ(
192209
(kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
193210
__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
194-
#endif
211+
# endif
195212

196213
// Check the sanity of the defined memory ranges (there might be gaps).
197214
CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
@@ -236,9 +253,11 @@ void InitThreads() {
236253
}
237254

238255
bool MemIsApp(uptr p) {
239-
#if !defined(__x86_64__) // Memory outside the alias range has non-zero tags.
256+
// Memory outside the alias range has non-zero tags.
257+
# if !defined(HWASAN_ALIASING_MODE)
240258
CHECK(GetTagFromPointer(p) == 0);
241-
#endif
259+
# endif
260+
242261
return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
243262
}
244263

0 commit comments

Comments
 (0)