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 Mastetick(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 Mastefuzz_clock_reset(void) 78f540a430SEd Maste { 79f540a430SEd Maste memset(&fuzz_clock, 0, sizeof(fuzz_clock)); 80f540a430SEd Maste } 81