1//===-- interception_aix.cpp ------------------------------------*- 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// This file is a part of AddressSanitizer, an address sanity checker.
10//
11// AIX-specific interception methods.
12//===----------------------------------------------------------------------===//
13
14#include "interception.h"
15#include "sanitizer_common/sanitizer_common.h"
16
17#if SANITIZER_AIX
18
19# include <dlfcn.h> // for dlsym()
20# include <stddef.h> // for size_t
21
22# if SANITIZER_WORDSIZE == 64
23# define STRCPY_STR "___strcpy64"
24# define MEMCPY_STR "___memcpy64"
25# define MEMMOVE_STR "___memmove64"
26# else
27# define STRCPY_STR "___strcpy"
28# define MEMCPY_STR "___memcpy"
29# define MEMMOVE_STR "___memmove"
30# endif
31
32namespace __interception {
33
34// These symbols cannot be used for indirect calls.
35char* ___strcpy(char*, const char*) __asm__(STRCPY_STR);
36char* ___memcpy(char*, const char*, size_t) __asm__(MEMCPY_STR);
37char* ___memmove(char*, const char*, size_t) __asm__(MEMMOVE_STR);
38
39static char* real_strcpy_wrapper(char* s1, const char* s2) {
40 return (char*)___strcpy(s1, s2);
41}
42
43static char* real_memcpy_wrapper(char* s1, const char* s2, size_t n) {
44 return (char*)___memcpy(s1, s2, n);
45}
46
47static char* real_memmove_wrapper(char* s1, const char* s2, size_t n) {
48 return (char*)___memmove(s1, s2, n);
49}
50
51static void* GetFuncAddr(const char* name, uptr wrapper_addr) {
52 // FIXME: if we are going to ship dynamic asan library, we may need to search
53 // all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed.
54 void *addr = dlsym(RTLD_NEXT, name);
55
56 // AIX dlsym can only detect functions that are exported, so
57 // some basic functions like memcpy return null. In this case, we fall back
58 // to a corresponding internal libc symbol (for example, ___memcpy) if it's
59 // available and, otherwise, to the internal sanitizer function.
60 if (!addr) {
61 if (internal_strcmp(name, "strcpy") == 0)
62 addr = (void*)real_strcpy_wrapper;
63 else if (internal_strcmp(name, "strncpy") == 0)
64 addr = (void*)internal_strncpy;
65 else if (internal_strcmp(name, "strcat") == 0)
66 addr = (void*)internal_strcat;
67 else if (internal_strcmp(name, "strncat") == 0)
68 addr = (void*)internal_strncat;
69 else if (internal_strcmp(name, "memcpy") == 0)
70 addr = (void*)real_memcpy_wrapper;
71 else if (internal_strcmp(name, "memmove") == 0)
72 addr = (void*)real_memmove_wrapper;
73 }
74
75 // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
76 // We don't want to intercept the wrapper and have it point to itself.
77 if ((uptr)addr == wrapper_addr)
78 addr = nullptr;
79 return addr;
80}
81
82bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
83 uptr wrapper) {
84 void *addr = GetFuncAddr(name, wrapper);
85 *ptr_to_real = (uptr)addr;
86 return addr && (func == wrapper);
87}
88
89} // namespace __interception
90#endif // SANITIZER_AIX
91