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