Skip to content

Commit

Permalink
Merge pull request #130 from nhorman/notime
Browse files Browse the repository at this point in the history
Notime
  • Loading branch information
nhorman committed Jun 11, 2021
2 parents 2f29afd + 6bc208d commit 9134cab
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 15 deletions.
5 changes: 4 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ AS_IF(
AC_MSG_NOTICE([Searching for jitterentropy library])
AC_SEARCH_LIBS(jent_version,jitterentropy,
[AM_CONDITIONAL([JITTER], [true])
AC_DEFINE([HAVE_JITTER],1,[Enable JITTER])],
AC_DEFINE([HAVE_JITTER],1,[Enable JITTER])
AC_CHECK_LIB(jitterentropy, jent_entropy_switch_notime_impl,
[AC_DEFINE([HAVE_JITTER_NOTIME],1,[Enable JITTER_NOTIME])],
[],-lpthread)],
AC_MSG_NOTICE([No Jitterentropy library found]),-lpthread)
], [AC_MSG_NOTICE([Disabling JITTER entropy source])]
)
Expand Down
2 changes: 2 additions & 0 deletions rngd.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ Options

\fBretry_delay - \fR between each retry for retry_count above, sleep for this many seconds. May also be the special value -1, representing adaptive sleep, where each retry delay will be half the recorded execution time of the last entropy gathering round (default -1)

\fBforce_soft_timer - \fR on platforms with a hardware timer that is too coarse to sample jitter, we can instead use a software based timer loop. Detection and use of this mechanism is automatic, but this can be useful for testing purposes

.TP
.B
PKCS11 (pkcs11) [Index 6]
Expand Down
5 changes: 5 additions & 0 deletions rngd.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ static struct rng_option jitter_options[] = {
.type = VAL_INT,
.int_val = 1,
},
[JITTER_OPT_FORCE_INT_TIMER] = {
.key = "force_soft_timer",
.type = VAL_INT,
.int_val = 0,
},
{
.key = NULL,
}
Expand Down
1 change: 1 addition & 0 deletions rngd.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ enum {
JITTER_OPT_RETRY_COUNT = 3,
JITTER_OPT_RETRY_DELAY = 4,
JITTER_OPT_USE_AES = 5,
JITTER_OPT_FORCE_INT_TIMER = 6,
JITTER_OPT_MAX,
};

Expand Down
111 changes: 97 additions & 14 deletions rngd_jitter.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,68 @@
#include "rngd_entsource.h"
#include "ossl_helpers.h"

static bool using_soft_timer = false;

#ifdef HAVE_JITTER_NOTIME
static int rngd_notime_start(void *ctx,
void *(*start_routine) (void *), void *arg)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
int ret;
int i;
cpu_set_t *cpus;
size_t cpusize;

if (!thread_ctx)
return -EINVAL;

ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr);
if (ret)
return ret;

/*
* the soft timer function should affine to all cpus
*/
i = sysconf(_SC_NPROCESSORS_CONF);
cpus = CPU_ALLOC(i);
cpusize = CPU_ALLOC_SIZE(i);
CPU_ZERO_S(cpusize, cpus);
for(i=i-1;i>=0;i--) {
CPU_SET(i,cpus);
}
pthread_attr_setaffinity_np(&thread_ctx->notime_pthread_attr, cpusize, cpus);

ret = -pthread_create(&thread_ctx->notime_thread_id,
&thread_ctx->notime_pthread_attr,
start_routine, arg);

CPU_FREE(cpus);
return ret;
}

static void rngd_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 int rngd_notime_init(void **ctx)
{
using_soft_timer = true;
return jent_notime_init(ctx);
}

static struct jent_notime_thread rngd_notime_thread_builtin = {
.jent_notime_init = rngd_notime_init,
.jent_notime_fini = jent_notime_fini,
.jent_notime_start = rngd_notime_start,
.jent_notime_stop = rngd_notime_stop
};
#endif

/* Read data from the drng in chunks of 128 bytes for AES scrambling */
#define CHUNK_SIZE (AES_BLOCK*8) /* 8 parallel streams */
#define RDRAND_ROUNDS 512 /* 512:1 data reduction */
Expand Down Expand Up @@ -259,6 +321,8 @@ int validate_jitter_options(struct rng *ent_src)
int refill = ent_src->rng_options[JITTER_OPT_REFILL].int_val;
int delay = ent_src->rng_options[JITTER_OPT_RETRY_DELAY].int_val;
int rcount = ent_src->rng_options[JITTER_OPT_RETRY_COUNT].int_val;
int soft_timer = ent_src->rng_options[JITTER_OPT_FORCE_INT_TIMER].int_val;
int num_threads = ent_src->rng_options[JITTER_OPT_THREADS].int_val;

/* Need at least one thread to do this work */
if (!threads) {
Expand All @@ -282,6 +346,12 @@ int validate_jitter_options(struct rng *ent_src)
return 1;
}

#ifndef HAVE_JITTER_NOTIME
if (soft_timer) {
message_entsrc(ent_src, LOG_DAEMON|LOG_ERR, "JITTER doesn't support soft timers in this build\n");
return 1;
}
#endif
return 0;
}

Expand All @@ -296,18 +366,31 @@ int init_jitter_entropy_source(struct rng *ent_src)
int i;
int size;
int flags;
int entflags = 0;
int ret;
int core_id = 0;

signal(SIGUSR1, jitter_thread_exit_signal);

int ret = jent_entropy_init();
if(ret) {
message_entsrc(ent_src,LOG_DAEMON|LOG_WARNING, "JITTER rng fails with code %d\n", ret);
if (validate_jitter_options(ent_src))
return 1;

#ifdef HAVE_JITTER_NOTIME
ret = jent_entropy_switch_notime_impl(&rngd_notime_thread_builtin);
if (ret) {
message_entsrc(ent_src, LOG_DAEMON|LOG_WARNING, "JITTER rng fails to register soft timer: %d\n", ret);
return 1;
}

if (validate_jitter_options(ent_src))
if (ent_src->rng_options[JITTER_OPT_FORCE_INT_TIMER].int_val)
entflags |= JENT_FORCE_INTERNAL_TIMER;
#endif

ret = jent_entropy_init();
if(ret) {
message_entsrc(ent_src,LOG_DAEMON|LOG_WARNING, "JITTER rng fails with code %d\n", ret);
return 1;
}

if (pipe(pipefds)) {
message_entsrc(ent_src,LOG_DAEMON|LOG_WARNING, "JITTER rng can't open pipe: %s\n", strerror(errno));
Expand Down Expand Up @@ -348,7 +431,7 @@ int init_jitter_entropy_source(struct rng *ent_src)
tdata = calloc(num_threads, sizeof(struct thread_data));
threads = calloc(num_threads, sizeof(pthread_t));

message_entsrc(ent_src,LOG_DAEMON|LOG_DEBUG, "JITTER starts %d threads\n", num_threads);
message_entsrc(ent_src,LOG_DAEMON|LOG_DEBUG, "JITTER attempting to start %d threads\n", num_threads);

/*
* Allocate and init the thread data that we need
Expand All @@ -364,17 +447,9 @@ int init_jitter_entropy_source(struct rng *ent_src)
tdata[i].done = -1;
core_id++;
tdata[i].buf_sz = ent_src->rng_options[JITTER_OPT_BUF_SZ].int_val;
tdata[i].ec = jent_entropy_collector_alloc(1, 0);
tdata[i].ec = jent_entropy_collector_alloc(1, entflags);
tdata[i].slpmode = ent_src->rng_options[JITTER_OPT_RETRY_DELAY].int_val;
pthread_create(&threads[i], NULL, thread_entropy_task, &tdata[i]);
}

CPU_FREE(cpus);
cpus = NULL;

/* Make sure all our threads are doing their jobs */
for (i=0; i < num_threads; i++) {
/* wait until the done state transitions from negative to zero or more */
pthread_mutex_lock(&tdata[i].statemtx);
if (tdata[i].done < 0)
pthread_cond_wait(&tdata[i].statecond, &tdata[i].statemtx);
Expand All @@ -384,8 +459,16 @@ int init_jitter_entropy_source(struct rng *ent_src)
else
message_entsrc(ent_src,LOG_DAEMON|LOG_DEBUG, "CPU Thread %d is ready\n", i);
pthread_mutex_unlock(&tdata[i].statemtx);
if (using_soft_timer == true) {
num_threads = 1;
message_entsrc(ent_src, LOG_DAEMON|LOG_INFO, "Limiting jitter to one thread for soft timer use\n");
break;
}
}

CPU_FREE(cpus);
cpus = NULL;

if (ent_src->rng_options[JITTER_OPT_USE_AES].int_val) {
/*
* Temporarily disable aes so we don't try to use it during init
Expand Down

0 comments on commit 9134cab

Please sign in to comment.