1 /* $OpenBSD: getentropy_hpux.c,v 1.8 2021/10/24 21:24:20 deraadt 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://man.openbsd.org/getentropy.2 21 */ 22 23 #include <sys/types.h> 24 #include <sys/param.h> 25 #include <sys/ioctl.h> 26 #include <sys/resource.h> 27 #include <sys/syscall.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 <openssl/sha.h> 45 46 #include <sys/vfs.h> 47 48 #include <sys/pstat.h> 49 50 #define REPEAT 5 51 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 52 53 #define HX(a, b) \ 54 do { \ 55 if ((a)) \ 56 HD(errno); \ 57 else \ 58 HD(b); \ 59 } while (0) 60 61 #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) 62 #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) 63 #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) 64 65 int getentropy(void *buf, size_t len); 66 67 static int getentropy_urandom(void *buf, size_t len, const char *path, 68 int devfscheck); 69 static int getentropy_fallback(void *buf, size_t len); 70 71 int 72 getentropy(void *buf, size_t len) 73 { 74 int ret = -1; 75 76 if (len > 256) { 77 errno = EIO; 78 return (-1); 79 } 80 81 /* 82 * Try to get entropy with /dev/urandom 83 */ 84 ret = getentropy_urandom(buf, len, "/dev/urandom", 0); 85 if (ret != -1) 86 return (ret); 87 88 /* 89 * Entropy collection via /dev/urandom has failed. 90 * 91 * No other API exists for collecting entropy, and we have 92 * no failsafe way to get it on hpux that is not sensitive 93 * to resource exhaustion. 94 * 95 * We have very few options: 96 * - Even syslog_r is unsafe to call at this low level, so 97 * there is no way to alert the user or program. 98 * - Cannot call abort() because some systems have unsafe 99 * corefiles. 100 * - Could raise(SIGKILL) resulting in silent program termination. 101 * - Return EIO, to hint that arc4random's stir function 102 * should raise(SIGKILL) 103 * - Do the best under the circumstances.... 104 * 105 * This code path exists to bring light to the issue that hpux 106 * does not provide a failsafe API for entropy collection. 107 * 108 * We hope this demonstrates that hpux should consider 109 * providing a new failsafe API which works in a chroot or 110 * when file descriptors are exhausted. 111 */ 112 #undef FAIL_INSTEAD_OF_TRYING_FALLBACK 113 #ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK 114 raise(SIGKILL); 115 #endif 116 ret = getentropy_fallback(buf, len); 117 if (ret != -1) 118 return (ret); 119 120 errno = EIO; 121 return (ret); 122 } 123 124 static int 125 getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) 126 { 127 struct stat st; 128 size_t i; 129 int fd, flags; 130 int save_errno = errno; 131 132 start: 133 134 flags = O_RDONLY; 135 #ifdef O_NOFOLLOW 136 flags |= O_NOFOLLOW; 137 #endif 138 #ifdef O_CLOEXEC 139 flags |= O_CLOEXEC; 140 #endif 141 fd = open(path, flags); 142 if (fd == -1) { 143 if (errno == EINTR) 144 goto start; 145 goto nodevrandom; 146 } 147 #ifndef O_CLOEXEC 148 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 149 #endif 150 151 /* Lightly verify that the device node looks sane */ 152 if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { 153 close(fd); 154 goto nodevrandom; 155 } 156 for (i = 0; i < len; ) { 157 size_t wanted = len - i; 158 ssize_t ret = read(fd, (char *)buf + i, wanted); 159 160 if (ret == -1) { 161 if (errno == EAGAIN || errno == EINTR) 162 continue; 163 close(fd); 164 goto nodevrandom; 165 } 166 i += ret; 167 } 168 close(fd); 169 errno = save_errno; 170 return (0); /* satisfied */ 171 nodevrandom: 172 errno = EIO; 173 return (-1); 174 } 175 176 static const int cl[] = { 177 CLOCK_REALTIME, 178 #ifdef CLOCK_MONOTONIC 179 CLOCK_MONOTONIC, 180 #endif 181 #ifdef CLOCK_MONOTONIC_RAW 182 CLOCK_MONOTONIC_RAW, 183 #endif 184 #ifdef CLOCK_TAI 185 CLOCK_TAI, 186 #endif 187 #ifdef CLOCK_VIRTUAL 188 CLOCK_VIRTUAL, 189 #endif 190 #ifdef CLOCK_UPTIME 191 CLOCK_UPTIME, 192 #endif 193 #ifdef CLOCK_PROCESS_CPUTIME_ID 194 CLOCK_PROCESS_CPUTIME_ID, 195 #endif 196 #ifdef CLOCK_THREAD_CPUTIME_ID 197 CLOCK_THREAD_CPUTIME_ID, 198 #endif 199 }; 200 201 static int 202 getentropy_fallback(void *buf, size_t len) 203 { 204 uint8_t results[SHA512_DIGEST_LENGTH]; 205 int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat; 206 static int cnt; 207 struct timespec ts; 208 struct timeval tv; 209 struct pst_vminfo pvi; 210 struct pst_vm_status pvs; 211 struct pst_dynamic pdy; 212 struct rusage ru; 213 sigset_t sigset; 214 struct stat st; 215 SHA512_CTX ctx; 216 static pid_t lastpid; 217 pid_t pid; 218 size_t i, ii, m; 219 char *p; 220 221 pid = getpid(); 222 if (lastpid == pid) { 223 faster = 1; 224 repeat = 2; 225 } else { 226 faster = 0; 227 lastpid = pid; 228 repeat = REPEAT; 229 } 230 for (i = 0; i < len; ) { 231 int j; 232 SHA512_Init(&ctx); 233 for (j = 0; j < repeat; j++) { 234 HX((e = gettimeofday(&tv, NULL)) == -1, tv); 235 if (e != -1) { 236 cnt += (int)tv.tv_sec; 237 cnt += (int)tv.tv_usec; 238 } 239 240 HX(pstat_getvminfo(&pvi, sizeof(pvi), 1, 0) != 1, pvi); 241 HX(pstat_getprocvm(&pvs, sizeof(pvs), 0, 0) != 1, pvs); 242 243 for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) 244 HX(clock_gettime(cl[ii], &ts) == -1, ts); 245 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 252 if(pstat_getdynamic(&pdy, sizeof(pdy), 1, 0) != 1) { 253 HD(errno); 254 } else { 255 HD(pdy.psd_avg_1_min); 256 HD(pdy.psd_avg_5_min); 257 HD(pdy.psd_avg_15_min); 258 } 259 260 if (!faster) { 261 ts.tv_sec = 0; 262 ts.tv_nsec = 1; 263 (void) nanosleep(&ts, NULL); 264 } 265 266 HX(sigpending(&sigset) == -1, sigset); 267 HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, 268 sigset); 269 270 HF(getentropy); /* an addr in this library */ 271 HF(printf); /* an addr in libc */ 272 p = (char *)&p; 273 HD(p); /* an addr on stack */ 274 p = (char *)&errno; 275 HD(p); /* the addr of errno */ 276 277 if (i == 0) { 278 struct sockaddr_storage ss; 279 struct statvfs stvfs; 280 struct termios tios; 281 socklen_t ssl; 282 off_t off; 283 284 /* 285 * Prime-sized mappings encourage fragmentation; 286 * thus exposing some address entropy. 287 */ 288 struct mm { 289 size_t npg; 290 void *p; 291 } mm[] = { 292 { 17, MAP_FAILED }, { 3, MAP_FAILED }, 293 { 11, MAP_FAILED }, { 2, MAP_FAILED }, 294 { 5, MAP_FAILED }, { 3, MAP_FAILED }, 295 { 7, MAP_FAILED }, { 1, MAP_FAILED }, 296 { 57, MAP_FAILED }, { 3, MAP_FAILED }, 297 { 131, MAP_FAILED }, { 1, MAP_FAILED }, 298 }; 299 300 for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { 301 HX(mm[m].p = mmap(NULL, 302 mm[m].npg * pgs, 303 PROT_READ|PROT_WRITE, 304 MAP_PRIVATE|MAP_ANON, -1, 305 (off_t)0), mm[m].p); 306 if (mm[m].p != MAP_FAILED) { 307 size_t mo; 308 309 /* Touch some memory... */ 310 p = mm[m].p; 311 mo = cnt % 312 (mm[m].npg * pgs - 1); 313 p[mo] = 1; 314 cnt += (int)((long)(mm[m].p) 315 / pgs); 316 } 317 318 /* Check cnts and times... */ 319 for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); 320 ii++) { 321 HX((e = clock_gettime(cl[ii], 322 &ts)) == -1, ts); 323 if (e != -1) 324 cnt += (int)ts.tv_nsec; 325 } 326 327 HX((e = getrusage(RUSAGE_SELF, 328 &ru)) == -1, ru); 329 if (e != -1) { 330 cnt += (int)ru.ru_utime.tv_sec; 331 cnt += (int)ru.ru_utime.tv_usec; 332 } 333 } 334 335 for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { 336 if (mm[m].p != MAP_FAILED) 337 munmap(mm[m].p, mm[m].npg * pgs); 338 mm[m].p = MAP_FAILED; 339 } 340 341 HX(stat(".", &st) == -1, st); 342 HX(statvfs(".", &stvfs) == -1, stvfs); 343 344 HX(stat("/", &st) == -1, st); 345 HX(statvfs("/", &stvfs) == -1, stvfs); 346 347 HX((e = fstat(0, &st)) == -1, st); 348 if (e == -1) { 349 if (S_ISREG(st.st_mode) || 350 S_ISFIFO(st.st_mode) || 351 S_ISSOCK(st.st_mode)) { 352 HX(fstatvfs(0, &stvfs) == -1, 353 stvfs); 354 HX((off = lseek(0, (off_t)0, 355 SEEK_CUR)) < 0, off); 356 } 357 if (S_ISCHR(st.st_mode)) { 358 HX(tcgetattr(0, &tios) == -1, 359 tios); 360 } else if (S_ISSOCK(st.st_mode)) { 361 memset(&ss, 0, sizeof ss); 362 ssl = sizeof(ss); 363 HX(getpeername(0, 364 (void *)&ss, &ssl) == -1, 365 ss); 366 } 367 } 368 369 HX((e = getrusage(RUSAGE_CHILDREN, 370 &ru)) == -1, ru); 371 if (e != -1) { 372 cnt += (int)ru.ru_utime.tv_sec; 373 cnt += (int)ru.ru_utime.tv_usec; 374 } 375 } else { 376 /* Subsequent hashes absorb previous result */ 377 HD(results); 378 } 379 380 HX((e = gettimeofday(&tv, NULL)) == -1, tv); 381 if (e != -1) { 382 cnt += (int)tv.tv_sec; 383 cnt += (int)tv.tv_usec; 384 } 385 386 HD(cnt); 387 } 388 SHA512_Final(results, &ctx); 389 memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); 390 i += MINIMUM(sizeof(results), len - i); 391 } 392 explicit_bzero(&ctx, sizeof ctx); 393 explicit_bzero(results, sizeof results); 394 errno = save_errno; 395 return (0); /* satisfied */ 396 } 397