summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-kernel/linux/files/jitter.patch466
-rw-r--r--meta/recipes-kernel/linux/linux-yocto_6.5.bb3
2 files changed, 468 insertions, 1 deletions
diff --git a/meta/recipes-kernel/linux/files/jitter.patch b/meta/recipes-kernel/linux/files/jitter.patch
new file mode 100644
index 00000000000..d01d1e8e032
--- /dev/null
+++ b/meta/recipes-kernel/linux/files/jitter.patch
@@ -0,0 +1,466 @@
+Upstream-Status: Backport
+Signed-off-by: Ross Burton <ross.burton@arm.com>
+
+From 37f0316051a8c01e61d34cc6c4a9cc4f6a6fe9c9 Mon Sep 17 00:00:00 2001
+From: Joachim Vandersmissen <git@jvdsn.com>
+Date: Sun, 6 Aug 2023 14:19:03 -0500
+Subject: [PATCH] crypto: jitter - Add clarifying comments to Jitter Entropy
+ RCT cutoff values
+
+The RCT cutoff values are correct, but they don't exactly match the ones
+one would expect when computing them using the formula in SP800-90B. This
+discrepancy is due to the fact that the Jitter Entropy RCT starts at 1. To
+avoid any confusion by future reviewers, add some comments and explicitly
+subtract 1 from the "correct" cutoff values in the definitions.
+
+Signed-off-by: Joachim Vandersmissen <git@jvdsn.com>
+Reviewed-by: Stephan Mueller <smueller@chronox.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+
+crypto: jitter - add RCT/APT support for different OSRs
+
+The oversampling rate (OSR) value specifies the heuristically implied
+entropy in the recorded data - H_submitter = 1/osr. A different entropy
+estimate implies a different APT/RCT cutoff value. This change adds
+support for OSRs 1 through 15. This OSR can be selected by the caller
+of the Jitter RNG.
+
+For this patch, the caller still uses one hard-coded OSR. A subsequent
+patch allows this value to be configured.
+
+In addition, the power-up self test is adjusted as follows:
+
+* It allows the caller to provide an oversampling rate that should be
+tested with - commonly it should be the same as used for the actual
+runtime operation. This makes the power-up testing therefore consistent
+with the runtime operation.
+
+* It calls now jent_measure_jitter (i.e. collects the full entropy
+that can possibly be harvested by the Jitter RNG) instead of only
+jent_condition_data (which only returns the entropy harvested from
+the conditioning component). This should now alleviate reports where
+the Jitter RNG initialization thinks there is too little entropy.
+
+* The power-up test now solely relies on the (enhanced) APT and RCT
+test that is used as a health test at runtime.
+
+The code allowing the different OSRs as well as the power-up test
+changes are present in the user space version of the Jitter RNG 3.4.1
+and thus was already in production use for some time.
+
+Reported-by "Ospan, Abylay" <aospan@amazon.com>
+Signed-off-by: Stephan Mueller <smueller@chronox.de>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+---
+ crypto/jitterentropy-kcapi.c | 4 +-
+ crypto/jitterentropy.c | 229 ++++++++++++++++++-----------------
+ crypto/jitterentropy.h | 3 +-
+ 3 files changed, 123 insertions(+), 113 deletions(-)
+
+diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
+index 7d1463a1562ac..1de730f946830 100644
+--- a/crypto/jitterentropy-kcapi.c
++++ b/crypto/jitterentropy-kcapi.c
+@@ -245,7 +245,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm)
+ crypto_shash_init(sdesc);
+ rng->sdesc = sdesc;
+
+- rng->entropy_collector = jent_entropy_collector_alloc(1, 0, sdesc);
++ rng->entropy_collector = jent_entropy_collector_alloc(0, 0, sdesc);
+ if (!rng->entropy_collector) {
+ ret = -ENOMEM;
+ goto err;
+@@ -334,7 +334,7 @@ static int __init jent_mod_init(void)
+
+ desc->tfm = tfm;
+ crypto_shash_init(desc);
+- ret = jent_entropy_init(desc);
++ ret = jent_entropy_init(0, 0, desc);
+ shash_desc_zero(desc);
+ crypto_free_shash(tfm);
+ if (ret) {
+diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c
+index c7d7f2caa7793..1b99ffaa8c349 100644
+--- a/crypto/jitterentropy.c
++++ b/crypto/jitterentropy.c
+@@ -72,6 +72,8 @@ struct rand_data {
+ __u64 prev_time; /* SENSITIVE Previous time stamp */
+ __u64 last_delta; /* SENSITIVE stuck test */
+ __s64 last_delta2; /* SENSITIVE stuck test */
++
++ unsigned int flags; /* Flags used to initialize */
+ unsigned int osr; /* Oversample rate */
+ #define JENT_MEMORY_BLOCKS 64
+ #define JENT_MEMORY_BLOCKSIZE 32
+@@ -88,12 +90,9 @@ struct rand_data {
+ /* Repetition Count Test */
+ unsigned int rct_count; /* Number of stuck values */
+
+- /* Intermittent health test failure threshold of 2^-30 */
+-#define JENT_RCT_CUTOFF 30 /* Taken from SP800-90B sec 4.4.1 */
+-#define JENT_APT_CUTOFF 325 /* Taken from SP800-90B sec 4.4.2 */
+- /* Permanent health test failure threshold of 2^-60 */
+-#define JENT_RCT_CUTOFF_PERMANENT 60
+-#define JENT_APT_CUTOFF_PERMANENT 355
++ /* Adaptive Proportion Test cutoff values */
++ unsigned int apt_cutoff; /* Intermittent health test failure */
++ unsigned int apt_cutoff_permanent; /* Permanent health test failure */
+ #define JENT_APT_WINDOW_SIZE 512 /* Data window size */
+ /* LSB of time stamp to process */
+ #define JENT_APT_LSB 16
+@@ -118,6 +117,9 @@ struct rand_data {
+ * zero). */
+ #define JENT_ESTUCK 8 /* Too many stuck results during init. */
+ #define JENT_EHEALTH 9 /* Health test failed during initialization */
++#define JENT_ERCT 10 /* RCT failed during initialization */
++#define JENT_EHASH 11 /* Hash self test failed */
++#define JENT_EMEM 12 /* Can't allocate memory for initialization */
+
+ /*
+ * The output n bits can receive more than n bits of min entropy, of course,
+@@ -143,6 +145,48 @@ struct rand_data {
+ * This test complies with SP800-90B section 4.4.2.
+ ***************************************************************************/
+
++/*
++ * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B
++ * APT.
++ * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf
++ * In in the syntax of R, this is C = 2 + qbinom(1 − 2^(−30), 511, 2^(-1/osr)).
++ * (The original formula wasn't correct because the first symbol must
++ * necessarily have been observed, so there is no chance of observing 0 of these
++ * symbols.)
++ *
++ * For the alpha < 2^-53, R cannot be used as it uses a float data type without
++ * arbitrary precision. A SageMath script is used to calculate those cutoff
++ * values.
++ *
++ * For any value above 14, this yields the maximal allowable value of 512
++ * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that
++ * renders the test unable to fail).
++ */
++static const unsigned int jent_apt_cutoff_lookup[15] = {
++ 325, 422, 459, 477, 488, 494, 499, 502,
++ 505, 507, 508, 509, 510, 511, 512 };
++static const unsigned int jent_apt_cutoff_permanent_lookup[15] = {
++ 355, 447, 479, 494, 502, 507, 510, 512,
++ 512, 512, 512, 512, 512, 512, 512 };
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++static void jent_apt_init(struct rand_data *ec, unsigned int osr)
++{
++ /*
++ * Establish the apt_cutoff based on the presumed entropy rate of
++ * 1/osr.
++ */
++ if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) {
++ ec->apt_cutoff = jent_apt_cutoff_lookup[
++ ARRAY_SIZE(jent_apt_cutoff_lookup) - 1];
++ ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[
++ ARRAY_SIZE(jent_apt_cutoff_permanent_lookup) - 1];
++ } else {
++ ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1];
++ ec->apt_cutoff_permanent =
++ jent_apt_cutoff_permanent_lookup[osr - 1];
++ }
++}
+ /*
+ * Reset the APT counter
+ *
+@@ -183,12 +227,12 @@ static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
+ /* APT health test failure detection */
+ static int jent_apt_permanent_failure(struct rand_data *ec)
+ {
+- return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
++ return (ec->apt_count >= ec->apt_cutoff_permanent) ? 1 : 0;
+ }
+
+ static int jent_apt_failure(struct rand_data *ec)
+ {
+- return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
++ return (ec->apt_count >= ec->apt_cutoff) ? 1 : 0;
+ }
+
+ /***************************************************************************
+@@ -271,15 +315,28 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
+ return 0;
+ }
+
+-/* RCT health test failure detection */
++/*
++ * The cutoff value is based on the following consideration:
++ * alpha = 2^-30 or 2^-60 as recommended in SP800-90B.
++ * In addition, we require an entropy value H of 1/osr as this is the minimum
++ * entropy required to provide full entropy.
++ * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr deltas for
++ * inserting them into the entropy pool which should then have (close to)
++ * DATA_SIZE_BITS bits of entropy in the conditioned output.
++ *
++ * Note, ec->rct_count (which equals to value B in the pseudo code of SP800-90B
++ * section 4.4.1) starts with zero. Hence we need to subtract one from the
++ * cutoff value as calculated following SP800-90B. Thus
++ * C = ceil(-log_2(alpha)/H) = 30*osr or 60*osr.
++ */
+ static int jent_rct_permanent_failure(struct rand_data *ec)
+ {
+- return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
++ return (ec->rct_count >= (60 * ec->osr)) ? 1 : 0;
+ }
+
+ static int jent_rct_failure(struct rand_data *ec)
+ {
+- return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
++ return (ec->rct_count >= (30 * ec->osr)) ? 1 : 0;
+ }
+
+ /* Report of health test failures */
+@@ -444,7 +501,7 @@ static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+ *
+ * @return result of stuck test
+ */
+-static int jent_measure_jitter(struct rand_data *ec)
++static int jent_measure_jitter(struct rand_data *ec, __u64 *ret_current_delta)
+ {
+ __u64 time = 0;
+ __u64 current_delta = 0;
+@@ -468,6 +525,10 @@ static int jent_measure_jitter(struct rand_data *ec)
+ if (jent_condition_data(ec, current_delta, stuck))
+ stuck = 1;
+
++ /* return the raw entropy value */
++ if (ret_current_delta)
++ *ret_current_delta = current_delta;
++
+ return stuck;
+ }
+
+@@ -485,11 +546,11 @@ static void jent_gen_entropy(struct rand_data *ec)
+ safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
+
+ /* priming of the ->prev_time value */
+- jent_measure_jitter(ec);
++ jent_measure_jitter(ec, NULL);
+
+ while (!jent_health_failure(ec)) {
+ /* If a stuck measurement is received, repeat measurement */
+- if (jent_measure_jitter(ec))
++ if (jent_measure_jitter(ec, NULL))
+ continue;
+
+ /*
+@@ -550,7 +611,8 @@ int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ * Perform startup health tests and return permanent
+ * error if it fails.
+ */
+- if (jent_entropy_init(ec->hash_state))
++ if (jent_entropy_init(ec->osr, ec->flags,
++ ec->hash_state))
+ return -3;
+
+ return -2;
+@@ -600,11 +662,15 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+
+ /* verify and set the oversampling rate */
+ if (osr == 0)
+- osr = 1; /* minimum sampling rate is 1 */
++ osr = 1; /* H_submitter = 1 / osr */
+ entropy_collector->osr = osr;
++ entropy_collector->flags = flags;
+
+ entropy_collector->hash_state = hash_state;
+
++ /* Initialize the APT */
++ jent_apt_init(entropy_collector, osr);
++
+ /* fill the data pad with non-zero values */
+ jent_gen_entropy(entropy_collector);
+
+@@ -618,20 +684,14 @@ void jent_entropy_collector_free(struct rand_data *entropy_collector)
+ jent_zfree(entropy_collector);
+ }
+
+-int jent_entropy_init(void *hash_state)
++int jent_entropy_init(unsigned int osr, unsigned int flags, void *hash_state)
+ {
+- int i;
+- __u64 delta_sum = 0;
+- __u64 old_delta = 0;
+- unsigned int nonstuck = 0;
+- int time_backwards = 0;
+- int count_mod = 0;
+- int count_stuck = 0;
+- struct rand_data ec = { 0 };
+-
+- /* Required for RCT */
+- ec.osr = 1;
+- ec.hash_state = hash_state;
++ struct rand_data *ec;
++ int i, time_backwards = 0, ret = 0;
++
++ ec = jent_entropy_collector_alloc(osr, flags, hash_state);
++ if (!ec)
++ return JENT_EMEM;
+
+ /* We could perform statistical tests here, but the problem is
+ * that we only have a few loop counts to do testing. These
+@@ -660,31 +720,28 @@ int jent_entropy_init(void *hash_state)
+ #define TESTLOOPCOUNT 1024
+ #define CLEARCACHE 100
+ for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
+- __u64 time = 0;
+- __u64 time2 = 0;
+- __u64 delta = 0;
+- unsigned int lowdelta = 0;
+- int stuck;
++ __u64 start_time = 0, end_time = 0, delta = 0;
+
+ /* Invoke core entropy collection logic */
+- jent_get_nstime(&time);
+- ec.prev_time = time;
+- jent_condition_data(&ec, time, 0);
+- jent_get_nstime(&time2);
++ jent_measure_jitter(ec, &delta);
++ end_time = ec->prev_time;
++ start_time = ec->prev_time - delta;
+
+ /* test whether timer works */
+- if (!time || !time2)
+- return JENT_ENOTIME;
+- delta = jent_delta(time, time2);
++ if (!start_time || !end_time) {
++ ret = JENT_ENOTIME;
++ goto out;
++ }
++
+ /*
+ * test whether timer is fine grained enough to provide
+ * delta even when called shortly after each other -- this
+ * implies that we also have a high resolution timer
+ */
+- if (!delta)
+- return JENT_ECOARSETIME;
+-
+- stuck = jent_stuck(&ec, delta);
++ if (!delta || (end_time == start_time)) {
++ ret = JENT_ECOARSETIME;
++ goto out;
++ }
+
+ /*
+ * up to here we did not modify any variable that will be
+@@ -696,49 +753,9 @@ int jent_entropy_init(void *hash_state)
+ if (i < CLEARCACHE)
+ continue;
+
+- if (stuck)
+- count_stuck++;
+- else {
+- nonstuck++;
+-
+- /*
+- * Ensure that the APT succeeded.
+- *
+- * With the check below that count_stuck must be less
+- * than 10% of the overall generated raw entropy values
+- * it is guaranteed that the APT is invoked at
+- * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
+- */
+- if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
+- jent_apt_reset(&ec,
+- delta & JENT_APT_WORD_MASK);
+- }
+- }
+-
+- /* Validate health test result */
+- if (jent_health_failure(&ec))
+- return JENT_EHEALTH;
+-
+ /* test whether we have an increasing timer */
+- if (!(time2 > time))
++ if (!(end_time > start_time))
+ time_backwards++;
+-
+- /* use 32 bit value to ensure compilation on 32 bit arches */
+- lowdelta = time2 - time;
+- if (!(lowdelta % 100))
+- count_mod++;
+-
+- /*
+- * ensure that we have a varying delta timer which is necessary
+- * for the calculation of entropy -- perform this check
+- * only after the first loop is executed as we need to prime
+- * the old_data value
+- */
+- if (delta > old_delta)
+- delta_sum += (delta - old_delta);
+- else
+- delta_sum += (old_delta - delta);
+- old_delta = delta;
+ }
+
+ /*
+@@ -748,31 +765,23 @@ int jent_entropy_init(void *hash_state)
+ * should not fail. The value of 3 should cover the NTP case being
+ * performed during our test run.
+ */
+- if (time_backwards > 3)
+- return JENT_ENOMONOTONIC;
+-
+- /*
+- * Variations of deltas of time must on average be larger
+- * than 1 to ensure the entropy estimation
+- * implied with 1 is preserved
+- */
+- if ((delta_sum) <= 1)
+- return JENT_EVARVAR;
++ if (time_backwards > 3) {
++ ret = JENT_ENOMONOTONIC;
++ goto out;
++ }
+
+- /*
+- * Ensure that we have variations in the time stamp below 10 for at
+- * least 10% of all checks -- on some platforms, the counter increments
+- * in multiples of 100, but not always
+- */
+- if ((TESTLOOPCOUNT/10 * 9) < count_mod)
+- return JENT_ECOARSETIME;
++ /* Did we encounter a health test failure? */
++ if (jent_rct_failure(ec)) {
++ ret = JENT_ERCT;
++ goto out;
++ }
++ if (jent_apt_failure(ec)) {
++ ret = JENT_EHEALTH;
++ goto out;
++ }
+
+- /*
+- * If we have more than 90% stuck results, then this Jitter RNG is
+- * likely to not work well.
+- */
+- if ((TESTLOOPCOUNT/10 * 9) < count_stuck)
+- return JENT_ESTUCK;
++out:
++ jent_entropy_collector_free(ec);
+
+- return 0;
++ return ret;
+ }
+diff --git a/crypto/jitterentropy.h b/crypto/jitterentropy.h
+index 4c92176ea2b1d..626c6228b7e2b 100644
+--- a/crypto/jitterentropy.h
++++ b/crypto/jitterentropy.h
+@@ -9,7 +9,8 @@ extern int jent_hash_time(void *hash_state, __u64 time, u8 *addtl,
+ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len);
+
+ struct rand_data;
+-extern int jent_entropy_init(void *hash_state);
++extern int jent_entropy_init(unsigned int osr, unsigned int flags,
++ void *hash_state);
+ extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ unsigned int len);
+
+--
+2.34.1
+
diff --git a/meta/recipes-kernel/linux/linux-yocto_6.5.bb b/meta/recipes-kernel/linux/linux-yocto_6.5.bb
index e132d2a2eb3..14011c68837 100644
--- a/meta/recipes-kernel/linux/linux-yocto_6.5.bb
+++ b/meta/recipes-kernel/linux/linux-yocto_6.5.bb
@@ -42,7 +42,8 @@ KBRANCH:class-devupstream = "v6.5/base"
SRC_URI = "git://git.yoctoproject.org/linux-yocto.git;name=machine;branch=${KBRANCH};protocol=https \
git://git.yoctoproject.org/yocto-kernel-cache;type=kmeta;name=meta;branch=yocto-6.5;destsuffix=${KMETA};protocol=https \
- file://0001-locking-atomic-scripts-fix-fallback-ifdeffery.patch"
+ file://0001-locking-atomic-scripts-fix-fallback-ifdeffery.patch \
+ file://jitter.patch"
LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"
LINUX_VERSION ?= "6.5.5"