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