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