1 /* 2 * Copyright (c) 2021 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 */ 6 7 #include <stdint.h> 8 #include <time.h> 9 10 #include "mutator_aux.h" 11 12 /* 13 * A pseudo-random monotonic clock with a probabilistic discontinuity to 14 * the end of time (as measured by struct timespec). 15 */ 16 17 extern int prng_up; 18 extern int __wrap_clock_gettime(clockid_t, struct timespec *); 19 extern int __real_clock_gettime(clockid_t, struct timespec *); 20 extern int __wrap_usleep(unsigned int); 21 static TLS struct timespec fuzz_clock; 22 23 static void 24 tick(unsigned int usec) 25 { 26 long long drift; 27 28 /* 29 * Simulate a jump to the end of time with 0.125% probability. 30 * This condition should be gracefully handled by callers of 31 * clock_gettime(). 32 */ 33 if (uniform_random(800) < 1) { 34 fuzz_clock.tv_sec = LLONG_MAX; 35 fuzz_clock.tv_nsec = LONG_MAX; 36 return; 37 } 38 39 drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */ 40 if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) { 41 fuzz_clock_reset(); /* Not much we can do here. */ 42 } else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) { 43 fuzz_clock.tv_nsec += (long)(drift); 44 } else { 45 fuzz_clock.tv_sec += (long)(drift / 1000000000); 46 fuzz_clock.tv_nsec += (long)(drift % 1000000000); 47 } 48 } 49 50 int 51 __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) 52 { 53 if (!prng_up || clk_id != CLOCK_MONOTONIC) 54 return __real_clock_gettime(clk_id, tp); 55 if (uniform_random(400) < 1) 56 return -1; 57 58 tick(0); 59 *tp = fuzz_clock; 60 61 return 0; 62 } 63 64 int 65 __wrap_usleep(unsigned int usec) 66 { 67 if (uniform_random(400) < 1) 68 return -1; 69 70 tick(usec); 71 72 return 0; 73 } 74 75 void 76 fuzz_clock_reset(void) 77 { 78 memset(&fuzz_clock, 0, sizeof(fuzz_clock)); 79 } 80