Line | Count | Source (jump to first uncovered line) |
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 | 842k | { |
26 | 842k | 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 | 842k | if (uniform_random(800) < 1) { |
34 | 1.11k | fuzz_clock.tv_sec = LLONG_MAX; |
35 | 1.11k | fuzz_clock.tv_nsec = LONG_MAX; |
36 | 1.11k | return; |
37 | 1.11k | } |
38 | | |
39 | 841k | drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */ |
40 | 841k | if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) { |
41 | 942 | fuzz_clock_reset(); /* Not much we can do here. */ |
42 | 840k | } else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) { |
43 | 792k | fuzz_clock.tv_nsec += (long)(drift); |
44 | 792k | } else { |
45 | 47.8k | fuzz_clock.tv_sec += (long)(drift / 1000000000); |
46 | 47.8k | fuzz_clock.tv_nsec += (long)(drift % 1000000000); |
47 | 47.8k | } |
48 | 841k | } |
49 | | |
50 | | int |
51 | | __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) |
52 | 843k | { |
53 | 843k | if (!prng_up || clk_id != CLOCK_MONOTONIC) |
54 | 843k | return __real_clock_gettime(clk_id, tp); |
55 | 843k | if (uniform_random(400) < 1) |
56 | 1.57k | return -1; |
57 | | |
58 | 841k | tick(0); |
59 | 841k | *tp = fuzz_clock; |
60 | | |
61 | 841k | return 0; |
62 | 841k | } |
63 | | |
64 | | int |
65 | | __wrap_usleep(unsigned int usec) |
66 | 948 | { |
67 | 948 | if (uniform_random(400) < 1) |
68 | 4 | return -1; |
69 | | |
70 | 944 | tick(usec); |
71 | | |
72 | 944 | return 0; |
73 | 944 | } |
74 | | |
75 | | void |
76 | | fuzz_clock_reset(void) |
77 | 18.4k | { |
78 | 18.4k | memset(&fuzz_clock, 0, sizeof(fuzz_clock)); |
79 | 18.4k | } |