1 //===-- scudo_utils.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// Platform specific utility functions.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "scudo_utils.h"
15 
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdarg.h>
19 #include <unistd.h>
20 #if defined(__x86_64__) || defined(__i386__)
21 # include <cpuid.h>
22 #endif
23 #if defined(__arm__) || defined(__aarch64__)
24 # include <sys/auxv.h>
25 #endif
26 
27 // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less
28 //                complicated string formatting code. The following is a
29 //                temporary workaround to be able to use __sanitizer::VSNPrintf.
30 namespace __sanitizer {
31 
32 extern int VSNPrintf(char *buff, int buff_length, const char *format,
33                      va_list args);
34 
35 }  // namespace __sanitizer
36 
37 namespace __scudo {
38 
39 FORMAT(1, 2)
40 void NORETURN dieWithMessage(const char *Format, ...) {
41   // Our messages are tiny, 256 characters is more than enough.
42   char Message[256];
43   va_list Args;
44   va_start(Args, Format);
45   __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args);
46   va_end(Args);
47   RawWrite(Message);
48   Die();
49 }
50 
51 #if defined(__x86_64__) || defined(__i386__)
52 // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID.
53 // CRC32 requires the SSE 4.2 instruction set.
54 typedef struct {
55   u32 Eax;
56   u32 Ebx;
57   u32 Ecx;
58   u32 Edx;
59 } CPUIDRegs;
60 
61 static void getCPUID(CPUIDRegs *Regs, u32 Level)
62 {
63   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
64 }
65 
66 CPUIDRegs getCPUFeatures() {
67   CPUIDRegs VendorRegs = {};
68   getCPUID(&VendorRegs, 0);
69   bool IsIntel =
70       (VendorRegs.Ebx == signature_INTEL_ebx) &&
71       (VendorRegs.Edx == signature_INTEL_edx) &&
72       (VendorRegs.Ecx == signature_INTEL_ecx);
73   bool IsAMD =
74       (VendorRegs.Ebx == signature_AMD_ebx) &&
75       (VendorRegs.Edx == signature_AMD_edx) &&
76       (VendorRegs.Ecx == signature_AMD_ecx);
77   // Default to an empty feature set if not on a supported CPU.
78   CPUIDRegs FeaturesRegs = {};
79   if (IsIntel || IsAMD) {
80     getCPUID(&FeaturesRegs, 1);
81   }
82   return FeaturesRegs;
83 }
84 
85 #ifndef bit_SSE4_2
86 # define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
87 #endif
88 
89 bool testCPUFeature(CPUFeature Feature)
90 {
91   CPUIDRegs FeaturesRegs = getCPUFeatures();
92 
93   switch (Feature) {
94     case CRC32CPUFeature:  // CRC32 is provided by SSE 4.2.
95       return !!(FeaturesRegs.Ecx & bit_SSE4_2);
96     default:
97       break;
98   }
99   return false;
100 }
101 #elif defined(__arm__) || defined(__aarch64__)
102 // For ARM and AArch64, hardware CRC32 support is indicated in the
103 // AT_HWVAL auxiliary vector.
104 
105 #ifndef HWCAP_CRC32
106 # define HWCAP_CRC32 (1<<7)  // HWCAP_CRC32 is missing on older platforms.
107 #endif
108 
109 bool testCPUFeature(CPUFeature Feature) {
110   uptr HWCap = getauxval(AT_HWCAP);
111 
112   switch (Feature) {
113     case CRC32CPUFeature:
114       return !!(HWCap & HWCAP_CRC32);
115     default:
116       break;
117   }
118   return false;
119 }
120 #else
121 bool testCPUFeature(CPUFeature Feature) {
122   return false;
123 }
124 #endif  // defined(__x86_64__) || defined(__i386__)
125 
126 // readRetry will attempt to read Count bytes from the Fd specified, and if
127 // interrupted will retry to read additional bytes to reach Count.
128 static ssize_t readRetry(int Fd, u8 *Buffer, size_t Count) {
129   ssize_t AmountRead = 0;
130   while (static_cast<size_t>(AmountRead) < Count) {
131     ssize_t Result = read(Fd, Buffer + AmountRead, Count - AmountRead);
132     if (Result > 0)
133       AmountRead += Result;
134     else if (!Result)
135       break;
136     else if (errno != EINTR) {
137       AmountRead = -1;
138       break;
139     }
140   }
141   return AmountRead;
142 }
143 
144 static void fillRandom(u8 *Data, ssize_t Size) {
145   int Fd = open("/dev/urandom", O_RDONLY);
146   if (Fd < 0) {
147     dieWithMessage("ERROR: failed to open /dev/urandom.\n");
148   }
149   bool Success = readRetry(Fd, Data, Size) == Size;
150   close(Fd);
151   if (!Success) {
152     dieWithMessage("ERROR: failed to read enough data from /dev/urandom.\n");
153   }
154 }
155 
156 // Default constructor for Xorshift128Plus seeds the state with /dev/urandom.
157 // TODO(kostyak): investigate using getrandom() if available.
158 Xorshift128Plus::Xorshift128Plus() {
159   fillRandom(reinterpret_cast<u8 *>(State), sizeof(State));
160 }
161 
162 const static u32 CRC32Table[] = {
163   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
164   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
165   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
166   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
167   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
168   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
169   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
170   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
171   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
172   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
173   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
174   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
175   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
176   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
177   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
178   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
179   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
180   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
181   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
182   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
183   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
184   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
185   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
186   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
187   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
188   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
189   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
190   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
191   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
192   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
193   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
194   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
195   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
196   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
197   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
198   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
199   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
200   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
201   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
202   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
203   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
204   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
205   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
206 };
207 
208 u32 computeSoftwareCRC32(u32 Crc, uptr Data) {
209   for (uptr i = 0; i < sizeof(Data); i++) {
210     Crc = CRC32Table[(Crc ^ Data) & 0xff] ^ (Crc >> 8);
211     Data >>= 8;
212   }
213   return Crc;
214 }
215 
216 }  // namespace __scudo
217