1//===-- sanitizer_common_interceptors_memintrinsics.inc ---------*- 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// Memintrinsic function interceptors for tools like AddressSanitizer,
10// ThreadSanitizer, MemorySanitizer, etc.
11//
12// These interceptors are part of the common interceptors, but separated out so
13// that implementations may add them, if necessary, to a separate source file
14// that should define SANITIZER_COMMON_NO_REDEFINE_BUILTINS at the top.
15//
16// This file should be included into the tool's memintrinsic interceptor file,
17// which has to define its own macros:
18// COMMON_INTERCEPTOR_ENTER
19// COMMON_INTERCEPTOR_READ_RANGE
20// COMMON_INTERCEPTOR_WRITE_RANGE
21// COMMON_INTERCEPTOR_MEMSET_IMPL
22// COMMON_INTERCEPTOR_MEMMOVE_IMPL
23// COMMON_INTERCEPTOR_MEMCPY_IMPL
24// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
25//
26// The fortified _chk variants below reuse the macros above by default (a tool
27// may override the following to customize their behavior):
28// COMMON_INTERCEPTOR_MEMSET_CHK_IMPL
29// COMMON_INTERCEPTOR_MEMMOVE_CHK_IMPL
30// COMMON_INTERCEPTOR_MEMCPY_CHK_IMPL
31// COMMON_INTERCEPTOR_MEMPCPY_CHK_IMPL
32//===----------------------------------------------------------------------===//
33
34#ifdef SANITIZER_REDEFINE_BUILTINS_H
35#error "Define SANITIZER_COMMON_NO_REDEFINE_BUILTINS in .cpp file"
36#endif
37
38#include "interception/interception.h"
39#include "sanitizer_platform_interceptors.h"
40
41// Platform-specific options.
42#if SANITIZER_APPLE
43# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
44#elif SANITIZER_WINDOWS64
45# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
46#elif SANITIZER_AIX
47# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
48#else
49# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1
50#endif // SANITIZER_APPLE
51
52#ifndef COMMON_INTERCEPTOR_MEMSET_IMPL
53#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
54 { \
55 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
56 return internal_memset(dst, v, size); \
57 COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
58 if (common_flags()->intercept_intrin) \
59 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
60 return REAL(memset)(dst, v, size); \
61 }
62#endif
63
64#ifndef COMMON_INTERCEPTOR_MEMMOVE_IMPL
65#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size) \
66 { \
67 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
68 return internal_memmove(dst, src, size); \
69 COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size); \
70 if (common_flags()->intercept_intrin) { \
71 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
72 COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \
73 } \
74 return REAL(memmove)(dst, src, size); \
75 }
76#endif
77
78#ifndef COMMON_INTERCEPTOR_MEMCPY_IMPL
79#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size) \
80 { \
81 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
82 return internal_memmove(dst, src, size); \
83 } \
84 COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size); \
85 if (common_flags()->intercept_intrin) { \
86 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
87 COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \
88 } \
89 return REAL(memcpy)(dst, src, size); \
90 }
91#endif
92
93// __{memset,memmove,memcpy}_chk(dst, ..., size, dst_size) abort when the
94// operation would write more than dst_size bytes, and otherwise behave exactly
95// like the corresponding plain function. So the overflow case is forwarded to
96// the real fortified function, and every other case is handled by the tool's
97// normal implementation, which is semantically identical and applies the usual
98// instrumentation.
99//
100// The overflow case deliberately calls the real function rather than Die() or
101// the libc's failure hook directly:
102// - Portability. glibc exports __chk_fail(), but Bionic (__fortify_fatal),
103// Apple (__chk_fail_overflow) and FreeBSD all use different, mostly
104// unexported entry points, and glibc's __fortify_fail is GLIBC_PRIVATE.
105// - Diagnostics. Each libc prints its own message, and Bionic even reports
106// the offending sizes. Delegating reproduces that for free.
107// - Consistency. Termination stays identical to an uninstrumented build, and
108// to the tools which do not intercept these at all (e.g. lsan and ubsan).
109// Die() would instead exit silently, and only under some of the tools.
110// A stack trace is still available for the resulting abort via handle_abort=1.
111//
112// REAL() is not resolved yet while nothing is initialized, so the bound is
113// enforced with CHECK_LE there instead, and the plain implementation's own
114// early startup path performs the access.
115#ifndef COMMON_INTERCEPTOR_MEMSET_CHK_IMPL
116# define COMMON_INTERCEPTOR_MEMSET_CHK_IMPL(ctx, dst, v, size, dst_size) \
117 { \
118 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
119 CHECK_LE(size, dst_size); \
120 } else if (UNLIKELY(size > dst_size)) { \
121 return REAL(__memset_chk)(dst, v, size, dst_size); \
122 } \
123 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size); \
124 }
125#endif
126
127#ifndef COMMON_INTERCEPTOR_MEMMOVE_CHK_IMPL
128# define COMMON_INTERCEPTOR_MEMMOVE_CHK_IMPL(ctx, dst, src, size, dst_size) \
129 { \
130 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
131 CHECK_LE(size, dst_size); \
132 } else if (UNLIKELY(size > dst_size)) { \
133 return REAL(__memmove_chk)(dst, src, size, dst_size); \
134 } \
135 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size); \
136 }
137#endif
138
139#ifndef COMMON_INTERCEPTOR_MEMCPY_CHK_IMPL
140# define COMMON_INTERCEPTOR_MEMCPY_CHK_IMPL(ctx, dst, src, size, dst_size) \
141 { \
142 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
143 CHECK_LE(size, dst_size); \
144 } else if (UNLIKELY(size > dst_size)) { \
145 return REAL(__memcpy_chk)(dst, src, size, dst_size); \
146 } \
147 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); \
148 }
149#endif
150
151#ifndef COMMON_INTERCEPTOR_MEMPCPY_CHK_IMPL
152# define COMMON_INTERCEPTOR_MEMPCPY_CHK_IMPL(ctx, dst, src, size, dst_size) \
153 { \
154 if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
155 CHECK_LE(size, dst_size); \
156 } else if (UNLIKELY(size > dst_size)) { \
157 return REAL(__mempcpy_chk)(dst, src, size, dst_size); \
158 } \
159 return (char*)([&]() -> void* { \
160 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size); \
161 }()) + \
162 size; \
163 }
164#endif
165
166#if SANITIZER_INTERCEPT_MEMSET
167INTERCEPTOR(void *, memset, void *dst, int v, usize size) {
168 void *ctx;
169 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size);
170}
171
172#define INIT_MEMSET COMMON_INTERCEPT_FUNCTION(memset)
173#else
174#define INIT_MEMSET
175#endif
176
177#if SANITIZER_INTERCEPT_MEMMOVE
178INTERCEPTOR(void *, memmove, void *dst, const void *src, usize size) {
179 void *ctx;
180 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
181}
182
183#define INIT_MEMMOVE COMMON_INTERCEPT_FUNCTION(memmove)
184#else
185#define INIT_MEMMOVE
186#endif
187
188#if SANITIZER_INTERCEPT_MEMCPY
189INTERCEPTOR(void *, memcpy, void *dst, const void *src, usize size) {
190 // On OS X, calling internal_memcpy here will cause memory corruptions,
191 // because memcpy and memmove are actually aliases of the same
192 // implementation. We need to use internal_memmove here.
193 // N.B.: If we switch this to internal_ we'll have to use internal_memmove
194 // due to memcpy being an alias of memmove on OS X.
195 void *ctx;
196#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
197 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size);
198#else
199 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
200#endif
201}
202
203# if SANITIZER_WINDOWS64
204// On Win64, older CRTs export memcpy as an alias of memmove (same address),
205// while newer ones (vcruntime140.dll 14.38+) ship them as distinct exports
206// (memcpy became a jmp-rel32 stub to memmove). Intercept the memcpy export
207// only where it is distinct so that calls through it are checked. Always
208// forward REAL(memcpy) to the real memmove: memmove is a semantic superset of
209// memcpy, and the memcpy stub's resolved target may be the interceptor
210// already installed at the memmove entry, which would shadow-check (and
211// double-check) the runtime's internal copies (e.g. asan's Reallocate).
212// Requires INIT_MEMMOVE to have run first.
213# define INIT_MEMCPY \
214 do { \
215 ::__interception::OverrideFunctionIfNotAliased( \
216 "memcpy", (::__interception::uptr)WRAP(memcpy), \
217 /*orig_old_func=*/nullptr, "memmove"); \
218 ASSIGN_REAL(memcpy, memmove); \
219 CHECK(REAL(memcpy)); \
220 } while (false)
221# else
222# define INIT_MEMCPY \
223 do { \
224 if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { \
225 COMMON_INTERCEPT_FUNCTION(memcpy); \
226 } else { \
227 ASSIGN_REAL(memcpy, memmove); \
228 } \
229 CHECK(REAL(memcpy)); \
230 } while (false)
231# endif
232
233#else
234#define INIT_MEMCPY
235#endif
236
237#if SANITIZER_INTERCEPT_AEABI_MEM
238INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, usize size) {
239 void *ctx;
240 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
241}
242
243INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, usize size) {
244 void *ctx;
245 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
246}
247
248INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, usize size) {
249 void *ctx;
250 COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
251}
252
253INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, usize size) {
254 void *ctx;
255 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
256}
257
258INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, usize size) {
259 void *ctx;
260 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
261}
262
263INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, usize size) {
264 void *ctx;
265 COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
266}
267
268// Note the argument order.
269INTERCEPTOR(void *, __aeabi_memset, void *block, usize size, int c) {
270 void *ctx;
271 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
272}
273
274INTERCEPTOR(void *, __aeabi_memset4, void *block, usize size, int c) {
275 void *ctx;
276 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
277}
278
279INTERCEPTOR(void *, __aeabi_memset8, void *block, usize size, int c) {
280 void *ctx;
281 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
282}
283
284INTERCEPTOR(void *, __aeabi_memclr, void *block, usize size) {
285 void *ctx;
286 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
287}
288
289INTERCEPTOR(void *, __aeabi_memclr4, void *block, usize size) {
290 void *ctx;
291 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
292}
293
294INTERCEPTOR(void *, __aeabi_memclr8, void *block, usize size) {
295 void *ctx;
296 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
297}
298
299#define INIT_AEABI_MEM \
300 COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \
301 COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \
302 COMMON_INTERCEPT_FUNCTION(__aeabi_memmove8); \
303 COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy); \
304 COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy4); \
305 COMMON_INTERCEPT_FUNCTION(__aeabi_memcpy8); \
306 COMMON_INTERCEPT_FUNCTION(__aeabi_memset); \
307 COMMON_INTERCEPT_FUNCTION(__aeabi_memset4); \
308 COMMON_INTERCEPT_FUNCTION(__aeabi_memset8); \
309 COMMON_INTERCEPT_FUNCTION(__aeabi_memclr); \
310 COMMON_INTERCEPT_FUNCTION(__aeabi_memclr4); \
311 COMMON_INTERCEPT_FUNCTION(__aeabi_memclr8);
312#else
313#define INIT_AEABI_MEM
314#endif // SANITIZER_INTERCEPT_AEABI_MEM
315
316#if SANITIZER_INTERCEPT___BZERO
317INTERCEPTOR(void *, __bzero, void *block, usize size) {
318 void *ctx;
319 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
320}
321#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero);
322#else
323#define INIT___BZERO
324#endif // SANITIZER_INTERCEPT___BZERO
325
326#if SANITIZER_INTERCEPT_BZERO
327INTERCEPTOR(void *, bzero, void *block, usize size) {
328 void *ctx;
329 COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
330}
331#define INIT_BZERO COMMON_INTERCEPT_FUNCTION(bzero);
332#else
333#define INIT_BZERO
334#endif // SANITIZER_INTERCEPT_BZERO
335
336#if SANITIZER_INTERCEPT___MEMSET_CHK
337INTERCEPTOR(void*, __memset_chk, void* dst, int v, usize size, usize dst_size) {
338 void* ctx;
339 COMMON_INTERCEPTOR_MEMSET_CHK_IMPL(ctx, dst, v, size, dst_size);
340}
341# define INIT___MEMSET_CHK COMMON_INTERCEPT_FUNCTION(__memset_chk);
342#else
343# define INIT___MEMSET_CHK
344#endif // SANITIZER_INTERCEPT___MEMSET_CHK
345
346#if SANITIZER_INTERCEPT___MEMMOVE_CHK
347INTERCEPTOR(void*, __memmove_chk, void* dst, const void* src, usize size,
348 usize dst_size) {
349 void* ctx;
350 COMMON_INTERCEPTOR_MEMMOVE_CHK_IMPL(ctx, dst, src, size, dst_size);
351}
352# define INIT___MEMMOVE_CHK COMMON_INTERCEPT_FUNCTION(__memmove_chk);
353#else
354# define INIT___MEMMOVE_CHK
355#endif // SANITIZER_INTERCEPT___MEMMOVE_CHK
356
357#if SANITIZER_INTERCEPT___MEMCPY_CHK
358INTERCEPTOR(void*, __memcpy_chk, void* dst, const void* src, usize size,
359 usize dst_size) {
360 void* ctx;
361 COMMON_INTERCEPTOR_MEMCPY_CHK_IMPL(ctx, dst, src, size, dst_size);
362}
363# define INIT___MEMCPY_CHK COMMON_INTERCEPT_FUNCTION(__memcpy_chk);
364#else
365# define INIT___MEMCPY_CHK
366#endif // SANITIZER_INTERCEPT___MEMCPY_CHK
367
368#if SANITIZER_INTERCEPT___MEMPCPY_CHK
369INTERCEPTOR(void*, __mempcpy_chk, void* dst, const void* src, usize size,
370 usize dst_size) {
371 void* ctx;
372 COMMON_INTERCEPTOR_MEMPCPY_CHK_IMPL(ctx, dst, src, size, dst_size);
373}
374# define INIT___MEMPCPY_CHK COMMON_INTERCEPT_FUNCTION(__mempcpy_chk);
375#else
376# define INIT___MEMPCPY_CHK
377#endif // SANITIZER_INTERCEPT___MEMPCPY_CHK
378
379namespace __sanitizer {
380// This does not need to be called if InitializeCommonInterceptors() is called.
381void InitializeMemintrinsicInterceptors() {
382 INIT_MEMSET;
383 INIT_MEMMOVE;
384 INIT_MEMCPY;
385 INIT_AEABI_MEM;
386 INIT___BZERO;
387 INIT_BZERO;
388 INIT___MEMSET_CHK;
389 INIT___MEMMOVE_CHK;
390 INIT___MEMCPY_CHK;
391 INIT___MEMPCPY_CHK;
392}
393} // namespace __sanitizer
394