/* Jitter RNG: Internal timer implementation * * Copyright (C) 2021 - 2022, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-base.h" #include "jitterentropy-timer.h" #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER /*************************************************************************** * Thread handler ***************************************************************************/ JENT_PRIVATE_STATIC int jent_notime_init(void **ctx) { struct jent_notime_ctx *thread_ctx; long ncpu = jent_ncpu(); if (ncpu < 0) return (int)ncpu; /* We need at least two CPUs to enable the timer thread */ if (ncpu < 2) return -EOPNOTSUPP; thread_ctx = calloc(1, sizeof(struct jent_notime_ctx)); if (!thread_ctx) return -errno; *ctx = thread_ctx; return 0; } JENT_PRIVATE_STATIC void jent_notime_fini(void *ctx) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; if (thread_ctx) free(thread_ctx); } static int jent_notime_start(void *ctx, void *(*start_routine) (void *), void *arg) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; int ret; if (!thread_ctx) return -EINVAL; ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr); if (ret) return ret; return -pthread_create(&thread_ctx->notime_thread_id, &thread_ctx->notime_pthread_attr, start_routine, arg); } static void jent_notime_stop(void *ctx) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; pthread_join(thread_ctx->notime_thread_id, NULL); pthread_attr_destroy(&thread_ctx->notime_pthread_attr); } static struct jent_notime_thread jent_notime_thread_builtin = { .jent_notime_init = jent_notime_init, .jent_notime_fini = jent_notime_fini, .jent_notime_start = jent_notime_start, .jent_notime_stop = jent_notime_stop }; /*************************************************************************** * Timer-less timer replacement * * If there is no high-resolution hardware timer available, we create one * ourselves. This logic is only used when the initialization identifies * that no suitable time source is available. ***************************************************************************/ static int jent_force_internal_timer = 0; static int jent_notime_switch_blocked = 0; void jent_notime_block_switch(void) { jent_notime_switch_blocked = 1; } static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin; /** * Timer-replacement loop * * @brief The measurement loop triggers the read of the value from the * counter function. It conceptually acts as the low resolution * samples timer from a ring oscillator. */ static void *jent_notime_sample_timer(void *arg) { struct rand_data *ec = (struct rand_data *)arg; ec->notime_timer = 0; while (1) { if (ec->notime_interrupt) return NULL; ec->notime_timer++; } return NULL; } /* * Enable the clock: spawn a new thread that holds a counter. * * Note, although creating a thread is expensive, we do that every time a * caller wants entropy from us and terminate the thread afterwards. This * is to ensure an attacker cannot easily identify the ticking thread. */ int jent_notime_settick(struct rand_data *ec) { if (!ec->enable_notime || !notime_thread) return 0; ec->notime_interrupt = 0; ec->notime_prev_timer = 0; ec->notime_timer = 0; return notime_thread->jent_notime_start(ec->notime_thread_ctx, jent_notime_sample_timer, ec); } void jent_notime_unsettick(struct rand_data *ec) { if (!ec->enable_notime || !notime_thread) return; ec->notime_interrupt = 1; notime_thread->jent_notime_stop(ec->notime_thread_ctx); } void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) { if (ec->enable_notime) { /* * Allow the counting thread to be initialized and guarantee * that it ticked since last time we looked. * * Note, we do not use an atomic operation here for reading * jent_notime_timer since if this integer is garbled, it even * adds to entropy. But on most architectures, read/write * of an uint64_t should be atomic anyway. */ while (ec->notime_timer == ec->notime_prev_timer) jent_yield(); ec->notime_prev_timer = ec->notime_timer; *out = ec->notime_prev_timer; } else { jent_get_nstime(out); } } static inline int jent_notime_enable_thread(struct rand_data *ec) { if (notime_thread) return notime_thread->jent_notime_init(&ec->notime_thread_ctx); return 0; } void jent_notime_disable(struct rand_data *ec) { if (notime_thread) notime_thread->jent_notime_fini(ec->notime_thread_ctx); } int jent_notime_enable(struct rand_data *ec, unsigned int flags) { /* Use internal timer */ if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { /* Self test not run yet */ if (!jent_force_internal_timer && jent_time_entropy_init(ec->osr, flags | JENT_FORCE_INTERNAL_TIMER)) return EHEALTH; ec->enable_notime = 1; return jent_notime_enable_thread(ec); } return 0; } int jent_notime_switch(struct jent_notime_thread *new_thread) { if (jent_notime_switch_blocked) return -EAGAIN; notime_thread = new_thread; return 0; } void jent_notime_force(void) { jent_force_internal_timer = 1; } int jent_notime_forced(void) { return jent_force_internal_timer; } #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */