Source code pulled from OpenBSD for OpenNTPD. The place to contribute to this code is via the OpenBSD CVS tree.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
9.6 KiB

  1. /* $OpenBSD: getentropy_aix.c,v 1.6 2018/11/20 08:04:28 deraadt Exp $ */
  2. /*
  3. * Copyright (c) 2015 Michael Felt <aixtools@gmail.com>
  4. * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
  5. * Copyright (c) 2014 Bob Beck <beck@obtuse.com>
  6. *
  7. * Permission to use, copy, modify, and distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. *
  19. * Emulation of getentropy(2) as documented at:
  20. * http://man.openbsd.org/getentropy.2
  21. */
  22. /*
  23. * -lperfstat is needed for the psuedo entropy data
  24. */
  25. #include <sys/mman.h>
  26. #include <sys/procfs.h>
  27. #include <sys/protosw.h>
  28. #include <sys/resource.h>
  29. #include <sys/socket.h>
  30. #include <sys/stat.h>
  31. #include <sys/statvfs.h>
  32. #include <sys/timers.h>
  33. #include <errno.h>
  34. #include <fcntl.h>
  35. #include <signal.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <termios.h>
  39. #include <openssl/sha.h>
  40. #include <libperfstat.h>
  41. #define REPEAT 5
  42. #define min(a, b) (((a) < (b)) ? (a) : (b))
  43. #define HX(a, b) \
  44. do { \
  45. if ((a)) \
  46. HD(errno); \
  47. else \
  48. HD(b); \
  49. } while (0)
  50. #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
  51. #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
  52. #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
  53. int getentropy(void *buf, size_t len);
  54. static int getentropy_urandom(void *buf, size_t len, const char *path,
  55. int devfscheck);
  56. static int getentropy_fallback(void *buf, size_t len);
  57. int
  58. getentropy(void *buf, size_t len)
  59. {
  60. int ret = -1;
  61. if (len > 256) {
  62. errno = EIO;
  63. return (-1);
  64. }
  65. /*
  66. * Try to get entropy with /dev/urandom
  67. */
  68. ret = getentropy_urandom(buf, len, "/dev/urandom", 0);
  69. if (ret != -1)
  70. return (ret);
  71. /*
  72. * Entropy collection via /dev/urandom has failed.
  73. *
  74. * No other API exists for collecting entropy, and we have
  75. * no failsafe way to get it on AIX that is not sensitive
  76. * to resource exhaustion.
  77. *
  78. * We have very few options:
  79. * - Even syslog_r is unsafe to call at this low level, so
  80. * there is no way to alert the user or program.
  81. * - Cannot call abort() because some systems have unsafe
  82. * corefiles.
  83. * - Could raise(SIGKILL) resulting in silent program termination.
  84. * - Return EIO, to hint that arc4random's stir function
  85. * should raise(SIGKILL)
  86. * - Do the best under the circumstances....
  87. *
  88. * This code path exists to bring light to the issue that AIX
  89. * does not provide a failsafe API for entropy collection.
  90. *
  91. * We hope this demonstrates that AIX should consider
  92. * providing a new failsafe API which works in a chroot or
  93. * when file descriptors are exhausted.
  94. */
  95. #undef FAIL_INSTEAD_OF_TRYING_FALLBACK
  96. #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
  97. raise(SIGKILL);
  98. #endif
  99. ret = getentropy_fallback(buf, len);
  100. if (ret != -1)
  101. return (ret);
  102. errno = EIO;
  103. return (ret);
  104. }
  105. static int
  106. getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
  107. {
  108. struct stat st;
  109. size_t i;
  110. int fd, flags;
  111. int save_errno = errno;
  112. start:
  113. flags = O_RDONLY;
  114. #ifdef O_NOFOLLOW
  115. flags |= O_NOFOLLOW;
  116. #endif
  117. #ifdef O_CLOEXEC
  118. flags |= O_CLOEXEC;
  119. #endif
  120. fd = open(path, flags, 0);
  121. if (fd == -1) {
  122. if (errno == EINTR)
  123. goto start;
  124. goto nodevrandom;
  125. }
  126. #ifndef O_CLOEXEC
  127. fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
  128. #endif
  129. /* Lightly verify that the device node looks sane */
  130. if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
  131. close(fd);
  132. goto nodevrandom;
  133. }
  134. for (i = 0; i < len; ) {
  135. size_t wanted = len - i;
  136. ssize_t ret = read(fd, (char *)buf + i, wanted);
  137. if (ret == -1) {
  138. if (errno == EAGAIN || errno == EINTR)
  139. continue;
  140. close(fd);
  141. goto nodevrandom;
  142. }
  143. i += ret;
  144. }
  145. close(fd);
  146. errno = save_errno;
  147. return (0); /* satisfied */
  148. nodevrandom:
  149. errno = EIO;
  150. return (-1);
  151. }
  152. static const int cl[] = {
  153. CLOCK_REALTIME,
  154. #ifdef CLOCK_MONOTONIC
  155. CLOCK_MONOTONIC,
  156. #endif
  157. #ifdef CLOCK_MONOTONIC_RAW
  158. CLOCK_MONOTONIC_RAW,
  159. #endif
  160. #ifdef CLOCK_TAI
  161. CLOCK_TAI,
  162. #endif
  163. #ifdef CLOCK_VIRTUAL
  164. CLOCK_VIRTUAL,
  165. #endif
  166. #ifdef CLOCK_UPTIME
  167. CLOCK_UPTIME,
  168. #endif
  169. #ifdef CLOCK_PROCESS_CPUTIME_ID
  170. CLOCK_PROCESS_CPUTIME_ID,
  171. #endif
  172. #ifdef CLOCK_THREAD_CPUTIME_ID
  173. CLOCK_THREAD_CPUTIME_ID,
  174. #endif
  175. };
  176. static int
  177. getentropy_fallback(void *buf, size_t len)
  178. {
  179. uint8_t results[SHA512_DIGEST_LENGTH];
  180. int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat;
  181. static int cnt;
  182. struct timespec ts;
  183. struct timeval tv;
  184. perfstat_cpu_total_t cpustats;
  185. #ifdef _AIX61
  186. perfstat_cpu_total_wpar_t cpustats_wpar;
  187. #endif
  188. perfstat_partition_total_t lparstats;
  189. perfstat_disk_total_t diskinfo;
  190. perfstat_netinterface_total_t netinfo;
  191. struct rusage ru;
  192. sigset_t sigset;
  193. struct stat st;
  194. SHA512_CTX ctx;
  195. static pid_t lastpid;
  196. pid_t pid;
  197. size_t i, ii, m;
  198. char *p;
  199. pid = getpid();
  200. if (lastpid == pid) {
  201. faster = 1;
  202. repeat = 2;
  203. } else {
  204. faster = 0;
  205. lastpid = pid;
  206. repeat = REPEAT;
  207. }
  208. for (i = 0; i < len; ) {
  209. int j;
  210. SHA512_Init(&ctx);
  211. for (j = 0; j < repeat; j++) {
  212. HX((e = gettimeofday(&tv, NULL)) == -1, tv);
  213. if (e != -1) {
  214. cnt += (int)tv.tv_sec;
  215. cnt += (int)tv.tv_usec;
  216. }
  217. HX(perfstat_cpu_total(NULL, &cpustats,
  218. sizeof(cpustats), 1) == -1, cpustats);
  219. #ifdef _AIX61
  220. HX(perfstat_cpu_total_wpar(NULL, &cpustats_wpar,
  221. sizeof(cpustats_wpar), 1) == -1, cpustats_wpar);
  222. #endif
  223. HX(perfstat_partition_total(NULL, &lparstats,
  224. sizeof(lparstats), 1) == -1, lparstats);
  225. HX(perfstat_disk_total(NULL, &diskinfo,
  226. sizeof(diskinfo), 1) == -1, diskinfo);
  227. HX(perfstat_netinterface_total(NULL, &netinfo,
  228. sizeof(netinfo), 1) == -1, netinfo);
  229. for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
  230. HX(clock_gettime(cl[ii], &ts) == -1, ts);
  231. HX((pid = getpid()) == -1, pid);
  232. HX((pid = getsid(pid)) == -1, pid);
  233. HX((pid = getppid()) == -1, pid);
  234. HX((pid = getpgid(0)) == -1, pid);
  235. HX((e = getpriority(0, 0)) == -1, e);
  236. if (!faster) {
  237. ts.tv_sec = 0;
  238. ts.tv_nsec = 1;
  239. (void) nanosleep(&ts, NULL);
  240. }
  241. HX(sigpending(&sigset) == -1, sigset);
  242. HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
  243. sigset);
  244. HF(getentropy); /* an addr in this library */
  245. HF(printf); /* an addr in libc */
  246. p = (char *)&p;
  247. HD(p); /* an addr on stack */
  248. p = (char *)&errno;
  249. HD(p); /* the addr of errno */
  250. if (i == 0) {
  251. struct sockaddr_storage ss;
  252. struct statvfs stvfs;
  253. struct termios tios;
  254. socklen_t ssl;
  255. off_t off;
  256. /*
  257. * Prime-sized mappings encourage fragmentation;
  258. * thus exposing some address entropy.
  259. */
  260. struct mm {
  261. size_t npg;
  262. void *p;
  263. } mm[] = {
  264. { 17, MAP_FAILED }, { 3, MAP_FAILED },
  265. { 11, MAP_FAILED }, { 2, MAP_FAILED },
  266. { 5, MAP_FAILED }, { 3, MAP_FAILED },
  267. { 7, MAP_FAILED }, { 1, MAP_FAILED },
  268. { 57, MAP_FAILED }, { 3, MAP_FAILED },
  269. { 131, MAP_FAILED }, { 1, MAP_FAILED },
  270. };
  271. for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
  272. HX(mm[m].p = mmap(NULL,
  273. mm[m].npg * pgs,
  274. PROT_READ|PROT_WRITE,
  275. MAP_PRIVATE|MAP_ANON, -1,
  276. (off_t)0), mm[m].p);
  277. if (mm[m].p != MAP_FAILED) {
  278. size_t mo;
  279. /* Touch some memory... */
  280. p = mm[m].p;
  281. mo = cnt %
  282. (mm[m].npg * pgs - 1);
  283. p[mo] = 1;
  284. cnt += (int)((long)(mm[m].p)
  285. / pgs);
  286. }
  287. /* Check cnts and times... */
  288. for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]);
  289. ii++) {
  290. HX((e = clock_gettime(cl[ii],
  291. &ts)) == -1, ts);
  292. if (e != -1)
  293. cnt += (int)ts.tv_nsec;
  294. }
  295. HX((e = getrusage(RUSAGE_SELF,
  296. &ru)) == -1, ru);
  297. if (e != -1) {
  298. cnt += (int)ru.ru_utime.tv_sec;
  299. cnt += (int)ru.ru_utime.tv_usec;
  300. }
  301. }
  302. for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
  303. if (mm[m].p != MAP_FAILED)
  304. munmap(mm[m].p, mm[m].npg * pgs);
  305. mm[m].p = MAP_FAILED;
  306. }
  307. HX(stat(".", &st) == -1, st);
  308. HX(statvfs(".", &stvfs) == -1, stvfs);
  309. HX(stat("/", &st) == -1, st);
  310. HX(statvfs("/", &stvfs) == -1, stvfs);
  311. HX((e = fstat(0, &st)) == -1, st);
  312. if (e == -1) {
  313. if (S_ISREG(st.st_mode) ||
  314. S_ISFIFO(st.st_mode) ||
  315. S_ISSOCK(st.st_mode)) {
  316. HX(fstatvfs(0, &stvfs) == -1,
  317. stvfs);
  318. HX((off = lseek(0, (off_t)0,
  319. SEEK_CUR)) < 0, off);
  320. }
  321. if (S_ISCHR(st.st_mode)) {
  322. HX(tcgetattr(0, &tios) == -1,
  323. tios);
  324. } else if (S_ISSOCK(st.st_mode)) {
  325. memset(&ss, 0, sizeof ss);
  326. ssl = sizeof(ss);
  327. HX(getpeername(0,
  328. (void *)&ss, &ssl) == -1,
  329. ss);
  330. }
  331. }
  332. HX((e = getrusage(RUSAGE_CHILDREN,
  333. &ru)) == -1, ru);
  334. if (e != -1) {
  335. cnt += (int)ru.ru_utime.tv_sec;
  336. cnt += (int)ru.ru_utime.tv_usec;
  337. }
  338. } else {
  339. /* Subsequent hashes absorb previous result */
  340. HD(results);
  341. }
  342. HX((e = gettimeofday(&tv, NULL)) == -1, tv);
  343. if (e != -1) {
  344. cnt += (int)tv.tv_sec;
  345. cnt += (int)tv.tv_usec;
  346. }
  347. HD(cnt);
  348. }
  349. SHA512_Final(results, &ctx);
  350. memcpy((char *)buf + i, results, min(sizeof(results), len - i));
  351. i += min(sizeof(results), len - i);
  352. }
  353. explicit_bzero(&ctx, sizeof ctx);
  354. explicit_bzero(results, sizeof results);
  355. errno = save_errno;
  356. return (0); /* satisfied */
  357. }