• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/json-c/random_seed.c

  1 /*
  2  * random_seed.c
  3  *
  4  * Copyright (c) 2013 Metaparadigm Pte. Ltd.
  5  * Michael Clark <michael@metaparadigm.com>
  6  *
  7  * This library is free software; you can redistribute it and/or modify
  8  * it under the terms of the MIT license. See COPYING for details.
  9  *
 10  */
 11 
 12 #include "random_seed.h"
 13 #include "config.h"
 14 #include "strerror_override.h"
 15 #include <stdio.h>
 16 
 17 #define DEBUG_SEED(s)
 18 
 19 #if defined ENABLE_RDRAND
 20 
 21 /* cpuid */
 22 
 23 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
 24 #define HAS_X86_CPUID 1
 25 
 26 static void do_cpuid(int regs[], int h)
 27 {
 28         /* clang-format off */
 29     __asm__ __volatile__("cpuid"
 30                          : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
 31                          : "a"(h));
 32         /* clang-format on */
 33 }
 34 
 35 #elif defined _MSC_VER
 36 
 37 #define HAS_X86_CPUID 1
 38 #define do_cpuid __cpuid
 39 
 40 #endif
 41 
 42 /* has_rdrand */
 43 
 44 #if HAS_X86_CPUID
 45 
 46 static int get_rdrand_seed(void);
 47 
 48 /* Valid values are -1 (haven't tested), 0 (no), and 1 (yes). */
 49 static int _has_rdrand = -1;
 50 
 51 static int has_rdrand(void)
 52 {
 53         if (_has_rdrand != -1)
 54         {
 55                 return _has_rdrand;
 56         }
 57 
 58         /* CPUID.01H:ECX.RDRAND[bit 30] == 1 */
 59         int regs[4];
 60         do_cpuid(regs, 1);
 61         if (!(regs[2] & (1 << 30)))
 62         {
 63                 _has_rdrand = 0;
 64                 return 0;
 65         }
 66 
 67         /*
 68          * Some CPUs advertise RDRAND in CPUID, but return 0xFFFFFFFF
 69          * unconditionally. To avoid locking up later, test RDRAND here. If over
 70          * 3 trials RDRAND has returned the same value, declare it broken.
 71          * Example CPUs are AMD Ryzen 3000 series
 72          * and much older AMD APUs, such as the E1-1500
 73          * https://github.com/systemd/systemd/issues/11810
 74          * https://linuxreviews.org/RDRAND_stops_returning_random_values_on_older_AMD_CPUs_after_suspend
 75          */
 76         _has_rdrand = 0;
 77         int prev = get_rdrand_seed();
 78         for (int i = 0; i < 3; i++)
 79         {
 80                 int temp = get_rdrand_seed();
 81                 if (temp != prev)
 82                 {
 83                         _has_rdrand = 1;
 84                         break;
 85                 }
 86 
 87                 prev = temp;
 88         }
 89 
 90         return _has_rdrand;
 91 }
 92 
 93 #endif
 94 
 95 /* get_rdrand_seed - GCC x86 and X64 */
 96 
 97 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
 98 
 99 #define HAVE_RDRAND 1
100 
101 static int get_rdrand_seed(void)
102 {
103         DEBUG_SEED("get_rdrand_seed");
104         int _eax;
105         /* rdrand eax */
106         /* clang-format off */
107         __asm__ __volatile__("1: .byte 0x0F\n"
108                              "   .byte 0xC7\n"
109                              "   .byte 0xF0\n"
110                              "   jnc 1b;\n"
111                              : "=a" (_eax));
112         /* clang-format on */
113         return _eax;
114 }
115 
116 #endif
117 
118 #if defined _MSC_VER
119 
120 #if _MSC_VER >= 1700
121 #define HAVE_RDRAND 1
122 
123 /* get_rdrand_seed - Visual Studio 2012 and above */
124 
125 static int get_rdrand_seed(void)
126 {
127         DEBUG_SEED("get_rdrand_seed");
128         int r;
129         while (_rdrand32_step(&r) == 0)
130                 ;
131         return r;
132 }
133 
134 #elif defined _M_IX86
135 #define HAVE_RDRAND 1
136 
137 /* get_rdrand_seed - Visual Studio 2010 and below - x86 only */
138 
139 /* clang-format off */
140 static int get_rdrand_seed(void)
141 {
142         DEBUG_SEED("get_rdrand_seed");
143         int _eax;
144 retry:
145         /* rdrand eax */
146         __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0
147         __asm jnc retry
148         __asm mov _eax, eax
149         return _eax;
150 }
151 /* clang-format on */
152 
153 #endif
154 #endif
155 
156 #endif /* defined ENABLE_RDRAND */
157 
158 /* has_dev_urandom */
159 
160 #if defined(__APPLE__) || defined(__unix__) || defined(__linux__)
161 
162 #include <fcntl.h>
163 #include <string.h>
164 #if HAVE_UNISTD_H
165 #include <unistd.h>
166 #endif /* HAVE_UNISTD_H */
167 #include <stdlib.h>
168 #include <sys/stat.h>
169 
170 #define HAVE_DEV_RANDOM 1
171 
172 static const char *dev_random_file = "/dev/urandom";
173 
174 static int has_dev_urandom(void)
175 {
176         struct stat buf;
177         if (stat(dev_random_file, &buf))
178         {
179                 return 0;
180         }
181         return ((buf.st_mode & S_IFCHR) != 0);
182 }
183 
184 /* get_dev_random_seed */
185 
186 static int get_dev_random_seed(void)
187 {
188         DEBUG_SEED("get_dev_random_seed");
189 
190         int fd = open(dev_random_file, O_RDONLY);
191         if (fd < 0)
192         {
193                 fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno));
194                 exit(1);
195         }
196 
197         int r;
198         ssize_t nread = read(fd, &r, sizeof(r));
199         if (nread != sizeof(r))
200         {
201                 fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno));
202                 exit(1);
203         }
204 
205         close(fd);
206         return r;
207 }
208 
209 #endif
210 
211 /* get_cryptgenrandom_seed */
212 
213 #ifdef WIN32
214 
215 #define HAVE_CRYPTGENRANDOM 1
216 
217 /* clang-format off */
218 #include <windows.h>
219 
220 /* Caution: these blank lines must remain so clang-format doesn't reorder
221    includes to put windows.h after wincrypt.h */
222 
223 #include <wincrypt.h>
224 /* clang-format on */
225 #ifndef __GNUC__
226 #pragma comment(lib, "advapi32.lib")
227 #endif
228 
229 static int get_time_seed(void);
230 
231 static int get_cryptgenrandom_seed(void)
232 {
233         HCRYPTPROV hProvider = 0;
234         DWORD dwFlags = CRYPT_VERIFYCONTEXT;
235         int r;
236 
237         DEBUG_SEED("get_cryptgenrandom_seed");
238 
239         /* WinNT 4 and Win98 do no support CRYPT_SILENT */
240         if (LOBYTE(LOWORD(GetVersion())) > 4)
241                 dwFlags |= CRYPT_SILENT;
242 
243         if (!CryptAcquireContextA(&hProvider, 0, 0, PROV_RSA_FULL, dwFlags))
244         {
245                 fprintf(stderr, "error CryptAcquireContextA 0x%08lx", GetLastError());
246                 r = get_time_seed();
247         }
248         else
249         {
250                 BOOL ret = CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r);
251                 CryptReleaseContext(hProvider, 0);
252                 if (!ret)
253                 {
254                         fprintf(stderr, "error CryptGenRandom 0x%08lx", GetLastError());
255                         r = get_time_seed();
256                 }
257         }
258 
259         return r;
260 }
261 
262 #endif
263 
264 /* get_time_seed */
265 
266 #include <time.h>
267 
268 static int get_time_seed(void)
269 {
270         DEBUG_SEED("get_time_seed");
271 
272         return (int)time(NULL) * 433494437;
273 }
274 
275 /* json_c_get_random_seed */
276 
277 int json_c_get_random_seed(void)
278 {
279 #ifdef OVERRIDE_GET_RANDOM_SEED
280         OVERRIDE_GET_RANDOM_SEED;
281 #endif
282 #if defined HAVE_RDRAND && HAVE_RDRAND
283         if (has_rdrand())
284                 return get_rdrand_seed();
285 #endif
286 #if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM
287         if (has_dev_urandom())
288                 return get_dev_random_seed();
289 #endif
290 #if defined HAVE_CRYPTGENRANDOM && HAVE_CRYPTGENRANDOM
291         return get_cryptgenrandom_seed();
292 #endif
293         return get_time_seed();
294 }
295 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt