lkml.org 
[lkml]   [2019]   [Mar]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.0 044/238] crypto: skcipher - set CRYPTO_TFM_NEED_KEY if ->setkey() fails
    Date
    5.0-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Eric Biggers <ebiggers@google.com>

    commit b1f6b4bf416b49f00f3abc49c639371cdecaaad1 upstream.

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    crypto/skcipher.c | 27 ++++++++++++++++++---------
    1 file changed, 18 insertions(+), 9 deletions(-)

    --- a/crypto/skcipher.c
    +++ b/crypto/skcipher.c
    @@ -585,6 +585,12 @@ static unsigned int crypto_skcipher_exts
    return crypto_alg_extsize(alg);
    }

    +static void skcipher_set_needkey(struct crypto_skcipher *tfm)
    +{
    + if (tfm->keysize)
    + crypto_skcipher_set_flags(tfm, CRYPTO_TFM_NEED_KEY);
    +}
    +
    static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm,
    const u8 *key, unsigned int keylen)
    {
    @@ -598,8 +604,10 @@ static int skcipher_setkey_blkcipher(str
    err = crypto_blkcipher_setkey(blkcipher, key, keylen);
    crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) &
    CRYPTO_TFM_RES_MASK);
    - if (err)
    + if (unlikely(err)) {
    + skcipher_set_needkey(tfm);
    return err;
    + }

    crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
    return 0;
    @@ -677,8 +685,7 @@ static int crypto_init_skcipher_ops_blkc
    skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher);
    skcipher->keysize = calg->cra_blkcipher.max_keysize;

    - if (skcipher->keysize)
    - crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY);
    + skcipher_set_needkey(skcipher);

    return 0;
    }
    @@ -698,8 +705,10 @@ static int skcipher_setkey_ablkcipher(st
    crypto_skcipher_set_flags(tfm,
    crypto_ablkcipher_get_flags(ablkcipher) &
    CRYPTO_TFM_RES_MASK);
    - if (err)
    + if (unlikely(err)) {
    + skcipher_set_needkey(tfm);
    return err;
    + }

    crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
    return 0;
    @@ -776,8 +785,7 @@ static int crypto_init_skcipher_ops_ablk
    sizeof(struct ablkcipher_request);
    skcipher->keysize = calg->cra_ablkcipher.max_keysize;

    - if (skcipher->keysize)
    - crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY);
    + skcipher_set_needkey(skcipher);

    return 0;
    }
    @@ -820,8 +828,10 @@ static int skcipher_setkey(struct crypto
    else
    err = cipher->setkey(tfm, key, keylen);

    - if (err)
    + if (unlikely(err)) {
    + skcipher_set_needkey(tfm);
    return err;
    + }

    crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
    return 0;
    @@ -852,8 +862,7 @@ static int crypto_skcipher_init_tfm(stru
    skcipher->ivsize = alg->ivsize;
    skcipher->keysize = alg->max_keysize;

    - if (skcipher->keysize)
    - crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY);
    + skcipher_set_needkey(skcipher);

    if (alg->exit)
    skcipher->base.exit = crypto_skcipher_exit_tfm;

    \
     
     \ /
      Last update: 2019-03-22 13:39    [W:4.813 / U:0.044 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site