getentropy_linux.c (12915B)
1 /* $OpenBSD: getentropy_linux.c,v 1.35 2014/08/28 01:00:57 bcook Exp $ */ 2 3 /* 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://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man2/getentropy.2 21 */ 22 23 #define _POSIX_C_SOURCE 199309L 24 #define _GNU_SOURCE 1 25 #include <sys/types.h> 26 #include <sys/param.h> 27 #include <sys/ioctl.h> 28 #include <sys/resource.h> 29 #include <sys/syscall.h> 30 #ifdef HAVE_SYS_SYSCTL_H 31 #include <sys/sysctl.h> 32 #endif 33 #include <sys/statvfs.h> 34 #include <sys/socket.h> 35 #include <sys/mount.h> 36 #include <sys/mman.h> 37 #include <sys/stat.h> 38 #include <sys/time.h> 39 #include <stdlib.h> 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <link.h> 43 #include <termios.h> 44 #include <fcntl.h> 45 #include <signal.h> 46 #include <string.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <time.h> 50 #include <openssl/sha.h> 51 52 #include <linux/types.h> 53 #include <linux/random.h> 54 #include <linux/sysctl.h> 55 #ifdef HAVE_GETAUXVAL 56 #include <sys/auxv.h> 57 #endif 58 #include <sys/vfs.h> 59 60 #define REPEAT 5 61 #define min(a, b) (((a) < (b)) ? (a) : (b)) 62 63 #define HX(a, b) \ 64 do { \ 65 if ((a)) \ 66 HD(errno); \ 67 else \ 68 HD(b); \ 69 } while (0) 70 71 #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) 72 #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) 73 #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) 74 75 int getentropy(void *buf, size_t len); 76 77 static int gotdata(char *buf, size_t len); 78 #ifdef SYS_getrandom 79 static int getentropy_getrandom(void *buf, size_t len); 80 #endif 81 static int getentropy_urandom(void *buf, size_t len); 82 #ifdef SYS__sysctl 83 static int getentropy_sysctl(void *buf, size_t len); 84 #endif 85 static int getentropy_fallback(void *buf, size_t len); 86 static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data); 87 88 int 89 getentropy(void *buf, size_t len) 90 { 91 int ret = -1; 92 93 if (len > 256) { 94 errno = EIO; 95 return -1; 96 } 97 98 #ifdef SYS_getrandom 99 /* 100 * Try descriptor-less getrandom() 101 */ 102 ret = getentropy_getrandom(buf, len); 103 if (ret != -1) 104 return (ret); 105 if (errno != ENOSYS) 106 return (-1); 107 #endif 108 109 /* 110 * Try to get entropy with /dev/urandom 111 * 112 * This can fail if the process is inside a chroot or if file 113 * descriptors are exhausted. 114 */ 115 ret = getentropy_urandom(buf, len); 116 if (ret != -1) 117 return (ret); 118 119 #ifdef SYS__sysctl 120 /* 121 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID. 122 * sysctl is a failsafe API, so it guarantees a result. This 123 * should work inside a chroot, or when file descriptors are 124 * exhuasted. 125 * 126 * However this can fail if the Linux kernel removes support 127 * for sysctl. Starting in 2007, there have been efforts to 128 * deprecate the sysctl API/ABI, and push callers towards use 129 * of the chroot-unavailable fd-using /proc mechanism -- 130 * essentially the same problems as /dev/urandom. 131 * 132 * Numerous setbacks have been encountered in their deprecation 133 * schedule, so as of June 2014 the kernel ABI still exists on 134 * most Linux architectures. The sysctl() stub in libc is missing 135 * on some systems. There are also reports that some kernels 136 * spew messages to the console. 137 */ 138 ret = getentropy_sysctl(buf, len); 139 if (ret != -1) 140 return (ret); 141 #endif /* SYS__sysctl */ 142 143 /* 144 * Entropy collection via /dev/urandom and sysctl have failed. 145 * 146 * No other API exists for collecting entropy. See the large 147 * comment block above. 148 * 149 * We have very few options: 150 * - Even syslog_r is unsafe to call at this low level, so 151 * there is no way to alert the user or program. 152 * - Cannot call abort() because some systems have unsafe 153 * corefiles. 154 * - Could raise(SIGKILL) resulting in silent program termination. 155 * - Return EIO, to hint that arc4random's stir function 156 * should raise(SIGKILL) 157 * - Do the best under the circumstances.... 158 * 159 * This code path exists to bring light to the issue that Linux 160 * does not provide a failsafe API for entropy collection. 161 * 162 * We hope this demonstrates that Linux should either retain their 163 * sysctl ABI, or consider providing a new failsafe API which 164 * works in a chroot or when file descriptors are exhausted. 165 */ 166 #undef FAIL_INSTEAD_OF_TRYING_FALLBACK 167 #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK 168 raise(SIGKILL); 169 #endif 170 ret = getentropy_fallback(buf, len); 171 if (ret != -1) 172 return (ret); 173 174 errno = EIO; 175 return (ret); 176 } 177 178 /* 179 * Basic sanity checking; wish we could do better. 180 */ 181 static int 182 gotdata(char *buf, size_t len) 183 { 184 char any_set = 0; 185 size_t i; 186 187 for (i = 0; i < len; ++i) 188 any_set |= buf[i]; 189 if (any_set == 0) 190 return -1; 191 return 0; 192 } 193 194 #ifdef SYS_getrandom 195 static int 196 getentropy_getrandom(void *buf, size_t len) 197 { 198 int pre_errno = errno; 199 int ret; 200 if (len > 256) 201 return (-1); 202 do { 203 ret = syscall(SYS_getrandom, buf, len, 0); 204 } while (ret == -1 && errno == EINTR); 205 206 if (ret != len) 207 return (-1); 208 errno = pre_errno; 209 return (0); 210 } 211 #endif 212 213 static int 214 getentropy_urandom(void *buf, size_t len) 215 { 216 struct stat st; 217 size_t i; 218 int fd, cnt, flags; 219 int save_errno = errno; 220 221 start: 222 223 flags = O_RDONLY; 224 #ifdef O_NOFOLLOW 225 flags |= O_NOFOLLOW; 226 #endif 227 #ifdef O_CLOEXEC 228 flags |= O_CLOEXEC; 229 #endif 230 fd = open("/dev/urandom", flags, 0); 231 if (fd == -1) { 232 if (errno == EINTR) 233 goto start; 234 goto nodevrandom; 235 } 236 #ifndef O_CLOEXEC 237 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 238 #endif 239 240 /* Lightly verify that the device node looks sane */ 241 if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { 242 close(fd); 243 goto nodevrandom; 244 } 245 if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) { 246 close(fd); 247 goto nodevrandom; 248 } 249 for (i = 0; i < len; ) { 250 size_t wanted = len - i; 251 ssize_t ret = read(fd, (char *)buf + i, wanted); 252 253 if (ret == -1) { 254 if (errno == EAGAIN || errno == EINTR) 255 continue; 256 close(fd); 257 goto nodevrandom; 258 } 259 i += ret; 260 } 261 close(fd); 262 if (gotdata(buf, len) == 0) { 263 errno = save_errno; 264 return 0; /* satisfied */ 265 } 266 nodevrandom: 267 errno = EIO; 268 return -1; 269 } 270 271 #ifdef SYS__sysctl 272 static int 273 getentropy_sysctl(void *buf, size_t len) 274 { 275 static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; 276 size_t i; 277 int save_errno = errno; 278 279 for (i = 0; i < len; ) { 280 size_t chunk = min(len - i, 16); 281 282 /* SYS__sysctl because some systems already removed sysctl() */ 283 struct __sysctl_args args = { 284 .name = mib, 285 .nlen = 3, 286 .oldval = (char *)buf + i, 287 .oldlenp = &chunk, 288 }; 289 if (syscall(SYS__sysctl, &args) != 0) 290 goto sysctlfailed; 291 i += chunk; 292 } 293 if (gotdata(buf, len) == 0) { 294 errno = save_errno; 295 return (0); /* satisfied */ 296 } 297 sysctlfailed: 298 errno = EIO; 299 return -1; 300 } 301 #endif /* SYS__sysctl */ 302 303 static int cl[] = { 304 CLOCK_REALTIME, 305 #ifdef CLOCK_MONOTONIC 306 CLOCK_MONOTONIC, 307 #endif 308 #ifdef CLOCK_MONOTONIC_RAW 309 CLOCK_MONOTONIC_RAW, 310 #endif 311 #ifdef CLOCK_TAI 312 CLOCK_TAI, 313 #endif 314 #ifdef CLOCK_VIRTUAL 315 CLOCK_VIRTUAL, 316 #endif 317 #ifdef CLOCK_UPTIME 318 CLOCK_UPTIME, 319 #endif 320 #ifdef CLOCK_PROCESS_CPUTIME_ID 321 CLOCK_PROCESS_CPUTIME_ID, 322 #endif 323 #ifdef CLOCK_THREAD_CPUTIME_ID 324 CLOCK_THREAD_CPUTIME_ID, 325 #endif 326 }; 327 328 static int 329 getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data) 330 { 331 SHA512_CTX *ctx = data; 332 333 SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr)); 334 return 0; 335 } 336 337 static int 338 getentropy_fallback(void *buf, size_t len) 339 { 340 uint8_t results[SHA512_DIGEST_LENGTH]; 341 int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; 342 static int cnt; 343 struct timespec ts; 344 struct timeval tv; 345 struct rusage ru; 346 sigset_t sigset; 347 struct stat st; 348 SHA512_CTX ctx; 349 static pid_t lastpid; 350 pid_t pid; 351 size_t i, ii, m; 352 char *p; 353 354 pid = getpid(); 355 if (lastpid == pid) { 356 faster = 1; 357 repeat = 2; 358 } else { 359 faster = 0; 360 lastpid = pid; 361 repeat = REPEAT; 362 } 363 for (i = 0; i < len; ) { 364 int j; 365 SHA512_Init(&ctx); 366 for (j = 0; j < repeat; j++) { 367 HX((e = gettimeofday(&tv, NULL)) == -1, tv); 368 if (e != -1) { 369 cnt += (int)tv.tv_sec; 370 cnt += (int)tv.tv_usec; 371 } 372 373 dl_iterate_phdr(getentropy_phdr, &ctx); 374 375 for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) 376 HX(clock_gettime(cl[ii], &ts) == -1, ts); 377 378 HX((pid = getpid()) == -1, pid); 379 HX((pid = getsid(pid)) == -1, pid); 380 HX((pid = getppid()) == -1, pid); 381 HX((pid = getpgid(0)) == -1, pid); 382 HX((e = getpriority(0, 0)) == -1, e); 383 384 if (!faster) { 385 ts.tv_sec = 0; 386 ts.tv_nsec = 1; 387 (void) nanosleep(&ts, NULL); 388 } 389 390 HX(sigpending(&sigset) == -1, sigset); 391 HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, 392 sigset); 393 394 HF(getentropy); /* an addr in this library */ 395 HF(printf); /* an addr in libc */ 396 p = (char *)&p; 397 HD(p); /* an addr on stack */ 398 p = (char *)&errno; 399 HD(p); /* the addr of errno */ 400 401 if (i == 0) { 402 struct sockaddr_storage ss; 403 struct statvfs stvfs; 404 struct termios tios; 405 struct statfs stfs; 406 socklen_t ssl; 407 off_t off; 408 409 /* 410 * Prime-sized mappings encourage fragmentation; 411 * thus exposing some address entropy. 412 */ 413 struct mm { 414 size_t npg; 415 void *p; 416 } mm[] = { 417 { 17, MAP_FAILED }, { 3, MAP_FAILED }, 418 { 11, MAP_FAILED }, { 2, MAP_FAILED }, 419 { 5, MAP_FAILED }, { 3, MAP_FAILED }, 420 { 7, MAP_FAILED }, { 1, MAP_FAILED }, 421 { 57, MAP_FAILED }, { 3, MAP_FAILED }, 422 { 131, MAP_FAILED }, { 1, MAP_FAILED }, 423 }; 424 425 for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { 426 HX(mm[m].p = mmap(NULL, 427 mm[m].npg * pgs, 428 PROT_READ|PROT_WRITE, 429 MAP_PRIVATE|MAP_ANON, -1, 430 (off_t)0), mm[m].p); 431 if (mm[m].p != MAP_FAILED) { 432 size_t mo; 433 434 /* Touch some memory... */ 435 p = mm[m].p; 436 mo = cnt % 437 (mm[m].npg * pgs - 1); 438 p[mo] = 1; 439 cnt += (int)((long)(mm[m].p) 440 / pgs); 441 } 442 443 /* Check cnts and times... */ 444 for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); 445 ii++) { 446 HX((e = clock_gettime(cl[ii], 447 &ts)) == -1, ts); 448 if (e != -1) 449 cnt += (int)ts.tv_nsec; 450 } 451 452 HX((e = getrusage(RUSAGE_SELF, 453 &ru)) == -1, ru); 454 if (e != -1) { 455 cnt += (int)ru.ru_utime.tv_sec; 456 cnt += (int)ru.ru_utime.tv_usec; 457 } 458 } 459 460 for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { 461 if (mm[m].p != MAP_FAILED) 462 munmap(mm[m].p, mm[m].npg * pgs); 463 mm[m].p = MAP_FAILED; 464 } 465 466 HX(stat(".", &st) == -1, st); 467 HX(statvfs(".", &stvfs) == -1, stvfs); 468 HX(statfs(".", &stfs) == -1, stfs); 469 470 HX(stat("/", &st) == -1, st); 471 HX(statvfs("/", &stvfs) == -1, stvfs); 472 HX(statfs("/", &stfs) == -1, stfs); 473 474 HX((e = fstat(0, &st)) == -1, st); 475 if (e == -1) { 476 if (S_ISREG(st.st_mode) || 477 S_ISFIFO(st.st_mode) || 478 S_ISSOCK(st.st_mode)) { 479 HX(fstatvfs(0, &stvfs) == -1, 480 stvfs); 481 HX(fstatfs(0, &stfs) == -1, 482 stfs); 483 HX((off = lseek(0, (off_t)0, 484 SEEK_CUR)) < 0, off); 485 } 486 if (S_ISCHR(st.st_mode)) { 487 HX(tcgetattr(0, &tios) == -1, 488 tios); 489 } else if (S_ISSOCK(st.st_mode)) { 490 memset(&ss, 0, sizeof ss); 491 ssl = sizeof(ss); 492 HX(getpeername(0, 493 (void *)&ss, &ssl) == -1, 494 ss); 495 } 496 } 497 498 HX((e = getrusage(RUSAGE_CHILDREN, 499 &ru)) == -1, ru); 500 if (e != -1) { 501 cnt += (int)ru.ru_utime.tv_sec; 502 cnt += (int)ru.ru_utime.tv_usec; 503 } 504 } else { 505 /* Subsequent hashes absorb previous result */ 506 HD(results); 507 } 508 509 HX((e = gettimeofday(&tv, NULL)) == -1, tv); 510 if (e != -1) { 511 cnt += (int)tv.tv_sec; 512 cnt += (int)tv.tv_usec; 513 } 514 515 HD(cnt); 516 } 517 #ifdef HAVE_GETAUXVAL 518 #ifdef AT_RANDOM 519 /* Not as random as you think but we take what we are given */ 520 p = (char *) getauxval(AT_RANDOM); 521 if (p) 522 HR(p, 16); 523 #endif 524 #ifdef AT_SYSINFO_EHDR 525 p = (char *) getauxval(AT_SYSINFO_EHDR); 526 if (p) 527 HR(p, pgs); 528 #endif 529 #ifdef AT_BASE 530 p = (char *) getauxval(AT_BASE); 531 if (p) 532 HD(p); 533 #endif 534 #endif 535 536 SHA512_Final(results, &ctx); 537 memcpy((char *)buf + i, results, min(sizeof(results), len - i)); 538 i += min(sizeof(results), len - i); 539 } 540 explicit_bzero(&ctx, sizeof ctx); 541 explicit_bzero(results, sizeof results); 542 if (gotdata(buf, len) == 0) { 543 errno = save_errno; 544 return 0; /* satisfied */ 545 } 546 errno = EIO; 547 return -1; 548 }