diff options
author | Eric Biggers <ebiggers@google.com> | 2019-01-06 21:47:43 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-01-18 05:40:24 -0500 |
commit | b1f6b4bf416b49f00f3abc49c639371cdecaaad1 (patch) | |
tree | ebdeae9666108a5ceac5e28a2138a967a149543d /crypto/skcipher.c | |
parent | ba7d7433a0e998c902132bd47330e355a1eaa894 (diff) |
crypto: skcipher - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
Some algorithms have a ->setkey() method that is not atomic, in the
sense that setting a key can fail after changes were already made to the
tfm context. In this case, if a key was already set the tfm can end up
in a state that corresponds to neither the old key nor the new key.
For example, in lrw.c, if gf128mul_init_64k_bbe() fails due to lack of
memory, then priv::table will be left NULL. After that, encryption with
that tfm will cause a NULL pointer dereference.
It's not feasible to make all ->setkey() methods atomic, especially ones
that have to key multiple sub-tfms. Therefore, make the crypto API set
CRYPTO_TFM_NEED_KEY if ->setkey() fails and the algorithm requires a
key, to prevent the tfm from being used until a new key is set.
[Cc stable mainly because when introducing the NEED_KEY flag I changed
AF_ALG to rely on it; and unlike in-kernel crypto API users, AF_ALG
previously didn't have this problem. So these "incompletely keyed"
states became theoretically accessible via AF_ALG -- though, the
opportunities for causing real mischief seem pretty limited.]
Fixes: f8d33fac8480 ("crypto: skcipher - prevent using skciphers without setting key")
Cc: <stable@vger.kernel.org> # v4.16+
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/skcipher.c')
-rw-r--r-- | crypto/skcipher.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 040ae6377b32..bcf13d95f54a 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c | |||
@@ -585,6 +585,12 @@ static unsigned int crypto_skcipher_extsize(struct crypto_alg *alg) | |||
585 | return crypto_alg_extsize(alg); | 585 | return crypto_alg_extsize(alg); |
586 | } | 586 | } |
587 | 587 | ||
588 | static void skcipher_set_needkey(struct crypto_skcipher *tfm) | ||
589 | { | ||
590 | if (tfm->keysize) | ||
591 | crypto_skcipher_set_flags(tfm, CRYPTO_TFM_NEED_KEY); | ||
592 | } | ||
593 | |||
588 | static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, | 594 | static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, |
589 | const u8 *key, unsigned int keylen) | 595 | const u8 *key, unsigned int keylen) |
590 | { | 596 | { |
@@ -598,8 +604,10 @@ static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, | |||
598 | err = crypto_blkcipher_setkey(blkcipher, key, keylen); | 604 | err = crypto_blkcipher_setkey(blkcipher, key, keylen); |
599 | crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & | 605 | crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & |
600 | CRYPTO_TFM_RES_MASK); | 606 | CRYPTO_TFM_RES_MASK); |
601 | if (err) | 607 | if (unlikely(err)) { |
608 | skcipher_set_needkey(tfm); | ||
602 | return err; | 609 | return err; |
610 | } | ||
603 | 611 | ||
604 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | 612 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
605 | return 0; | 613 | return 0; |
@@ -677,8 +685,7 @@ static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) | |||
677 | skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); | 685 | skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); |
678 | skcipher->keysize = calg->cra_blkcipher.max_keysize; | 686 | skcipher->keysize = calg->cra_blkcipher.max_keysize; |
679 | 687 | ||
680 | if (skcipher->keysize) | 688 | skcipher_set_needkey(skcipher); |
681 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
682 | 689 | ||
683 | return 0; | 690 | return 0; |
684 | } | 691 | } |
@@ -698,8 +705,10 @@ static int skcipher_setkey_ablkcipher(struct crypto_skcipher *tfm, | |||
698 | crypto_skcipher_set_flags(tfm, | 705 | crypto_skcipher_set_flags(tfm, |
699 | crypto_ablkcipher_get_flags(ablkcipher) & | 706 | crypto_ablkcipher_get_flags(ablkcipher) & |
700 | CRYPTO_TFM_RES_MASK); | 707 | CRYPTO_TFM_RES_MASK); |
701 | if (err) | 708 | if (unlikely(err)) { |
709 | skcipher_set_needkey(tfm); | ||
702 | return err; | 710 | return err; |
711 | } | ||
703 | 712 | ||
704 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | 713 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
705 | return 0; | 714 | return 0; |
@@ -776,8 +785,7 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) | |||
776 | sizeof(struct ablkcipher_request); | 785 | sizeof(struct ablkcipher_request); |
777 | skcipher->keysize = calg->cra_ablkcipher.max_keysize; | 786 | skcipher->keysize = calg->cra_ablkcipher.max_keysize; |
778 | 787 | ||
779 | if (skcipher->keysize) | 788 | skcipher_set_needkey(skcipher); |
780 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
781 | 789 | ||
782 | return 0; | 790 | return 0; |
783 | } | 791 | } |
@@ -820,8 +828,10 @@ static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, | |||
820 | else | 828 | else |
821 | err = cipher->setkey(tfm, key, keylen); | 829 | err = cipher->setkey(tfm, key, keylen); |
822 | 830 | ||
823 | if (err) | 831 | if (unlikely(err)) { |
832 | skcipher_set_needkey(tfm); | ||
824 | return err; | 833 | return err; |
834 | } | ||
825 | 835 | ||
826 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); | 836 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
827 | return 0; | 837 | return 0; |
@@ -852,8 +862,7 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) | |||
852 | skcipher->ivsize = alg->ivsize; | 862 | skcipher->ivsize = alg->ivsize; |
853 | skcipher->keysize = alg->max_keysize; | 863 | skcipher->keysize = alg->max_keysize; |
854 | 864 | ||
855 | if (skcipher->keysize) | 865 | skcipher_set_needkey(skcipher); |
856 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
857 | 866 | ||
858 | if (alg->exit) | 867 | if (alg->exit) |
859 | skcipher->base.exit = crypto_skcipher_exit_tfm; | 868 | skcipher->base.exit = crypto_skcipher_exit_tfm; |