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.

417 lines
10 KiB

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