xref: /freebsd/contrib/libfido2/fuzz/clock.c (revision 66fd12cf4896eb08ad8e7a2627537f84ead84dd3)
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