]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - crypto/drbg.c
net/mlx5: Fix some error handling paths in 'mlx5e_tc_add_fdb_flow()'
[mirror_ubuntu-jammy-kernel.git] / crypto / drbg.c
index ea85d4a0fe9e933044a5fcb76b0cd1e318d8ae33..761104e93d44a4ac6f9501add8e057659cc0a38f 100644 (file)
@@ -1036,17 +1036,38 @@ static const struct drbg_state_ops drbg_hash_ops = {
  ******************************************************************/
 
 static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
-                             int reseed)
+                             int reseed, enum drbg_seed_state new_seed_state)
 {
        int ret = drbg->d_ops->update(drbg, seed, reseed);
 
        if (ret)
                return ret;
 
-       drbg->seeded = true;
+       drbg->seeded = new_seed_state;
        /* 10.1.1.2 / 10.1.1.3 step 5 */
        drbg->reseed_ctr = 1;
 
+       switch (drbg->seeded) {
+       case DRBG_SEED_STATE_UNSEEDED:
+               /* Impossible, but handle it to silence compiler warnings. */
+               fallthrough;
+       case DRBG_SEED_STATE_PARTIAL:
+               /*
+                * Require frequent reseeds until the seed source is
+                * fully initialized.
+                */
+               drbg->reseed_threshold = 50;
+               break;
+
+       case DRBG_SEED_STATE_FULL:
+               /*
+                * Seed source has become fully initialized, frequent
+                * reseeds no longer required.
+                */
+               drbg->reseed_threshold = drbg_max_requests(drbg);
+               break;
+       }
+
        return ret;
 }
 
@@ -1066,12 +1087,10 @@ static inline int drbg_get_random_bytes(struct drbg_state *drbg,
        return 0;
 }
 
-static void drbg_async_seed(struct work_struct *work)
+static int drbg_seed_from_random(struct drbg_state *drbg)
 {
        struct drbg_string data;
        LIST_HEAD(seedlist);
-       struct drbg_state *drbg = container_of(work, struct drbg_state,
-                                              seed_work);
        unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
        unsigned char entropy[32];
        int ret;
@@ -1082,26 +1101,15 @@ static void drbg_async_seed(struct work_struct *work)
        drbg_string_fill(&data, entropy, entropylen);
        list_add_tail(&data.list, &seedlist);
 
-       mutex_lock(&drbg->drbg_mutex);
-
        ret = drbg_get_random_bytes(drbg, entropy, entropylen);
        if (ret)
-               goto unlock;
-
-       /* Set seeded to false so that if __drbg_seed fails the
-        * next generate call will trigger a reseed.
-        */
-       drbg->seeded = false;
-
-       __drbg_seed(drbg, &seedlist, true);
-
-       if (drbg->seeded)
-               drbg->reseed_threshold = drbg_max_requests(drbg);
+               goto out;
 
-unlock:
-       mutex_unlock(&drbg->drbg_mutex);
+       ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL);
 
+out:
        memzero_explicit(entropy, entropylen);
+       return ret;
 }
 
 /*
@@ -1123,6 +1131,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
        unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
        struct drbg_string data1;
        LIST_HEAD(seedlist);
+       enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL;
 
        /* 9.1 / 9.2 / 9.3.1 step 3 */
        if (pers && pers->len > (drbg_max_addtl(drbg))) {
@@ -1150,6 +1159,9 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                BUG_ON((entropylen * 2) > sizeof(entropy));
 
                /* Get seed from in-kernel /dev/urandom */
+               if (!rng_is_initialized())
+                       new_seed_state = DRBG_SEED_STATE_PARTIAL;
+
                ret = drbg_get_random_bytes(drbg, entropy, entropylen);
                if (ret)
                        goto out;
@@ -1206,7 +1218,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
                memset(drbg->C, 0, drbg_statelen(drbg));
        }
 
-       ret = __drbg_seed(drbg, &seedlist, reseed);
+       ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state);
 
 out:
        memzero_explicit(entropy, entropylen * 2);
@@ -1386,19 +1398,25 @@ static int drbg_generate(struct drbg_state *drbg,
         * here. The spec is a bit convoluted here, we make it simpler.
         */
        if (drbg->reseed_threshold < drbg->reseed_ctr)
-               drbg->seeded = false;
+               drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
 
-       if (drbg->pr || !drbg->seeded) {
+       if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) {
                pr_devel("DRBG: reseeding before generation (prediction "
                         "resistance: %s, state %s)\n",
                         drbg->pr ? "true" : "false",
-                        drbg->seeded ? "seeded" : "unseeded");
+                        (drbg->seeded ==  DRBG_SEED_STATE_FULL ?
+                         "seeded" : "unseeded"));
                /* 9.3.1 steps 7.1 through 7.3 */
                len = drbg_seed(drbg, addtl, true);
                if (len)
                        goto err;
                /* 9.3.1 step 7.4 */
                addtl = NULL;
+       } else if (rng_is_initialized() &&
+                  drbg->seeded == DRBG_SEED_STATE_PARTIAL) {
+               len = drbg_seed_from_random(drbg);
+               if (len)
+                       goto err;
        }
 
        if (addtl && 0 < addtl->len)
@@ -1491,51 +1509,15 @@ static int drbg_generate_long(struct drbg_state *drbg,
        return 0;
 }
 
-static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
-{
-       struct drbg_state *drbg = container_of(rdy, struct drbg_state,
-                                              random_ready);
-
-       schedule_work(&drbg->seed_work);
-}
-
 static int drbg_prepare_hrng(struct drbg_state *drbg)
 {
-       int err;
-
        /* We do not need an HRNG in test mode. */
        if (list_empty(&drbg->test_data.list))
                return 0;
 
        drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
 
-       INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
-       drbg->random_ready.owner = THIS_MODULE;
-       drbg->random_ready.func = drbg_schedule_async_seed;
-
-       err = add_random_ready_callback(&drbg->random_ready);
-
-       switch (err) {
-       case 0:
-               break;
-
-       case -EALREADY:
-               err = 0;
-               fallthrough;
-
-       default:
-               drbg->random_ready.func = NULL;
-               return err;
-       }
-
-       /*
-        * Require frequent reseeds until the seed source is fully
-        * initialized.
-        */
-       drbg->reseed_threshold = 50;
-
-       return err;
+       return 0;
 }
 
 /*
@@ -1578,7 +1560,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
        if (!drbg->core) {
                drbg->core = &drbg_cores[coreref];
                drbg->pr = pr;
-               drbg->seeded = false;
+               drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
                drbg->reseed_threshold = drbg_max_requests(drbg);
 
                ret = drbg_alloc_state(drbg);
@@ -1629,11 +1611,6 @@ free_everything:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-       if (drbg->random_ready.func) {
-               del_random_ready_callback(&drbg->random_ready);
-               cancel_work_sync(&drbg->seed_work);
-       }
-
        if (!IS_ERR_OR_NULL(drbg->jent))
                crypto_free_rng(drbg->jent);
        drbg->jent = NULL;