Patch "crypto: hash - prevent using keyed hashes without setting key" has been added to the 4.14-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
crypto: hash - prevent using keyed hashes without setting key
to the 4.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
crypto-hash-prevent-using-keyed-hashes-without-setting-key.patch
and it can be found in the queue-4.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
9fa68f620041be04720d0cbfb1bd3ddfc6310b24Mon Sep 17 00:00:00 2001
From: Eric Biggers <[email protected]>
Date: Wed, 3 Jan 2018 11:16:27 -0800
Subject: crypto: hash - prevent using keyed hashes without setting key
From: Eric Biggers <[email protected]>
commit 9fa68f620041be04720d0cbfb1bd3ddfc6310b24 upstream.
Currently, almost none of the keyed hash algorithms check whether a key has been set before proceeding. Some algorithms are okay with this and will effectively just use a key of all 0's or some other bogus default. However, others will severely break, as demonstrated using "hmac(sha3-512-generic)", the unkeyed use of which causes a kernel crash via a (potentially exploitable) stack buffer overflow.
A while ago, this problem was solved for AF_ALG by pairing each hash transform with a 'has_key' bool. However, there are still other places in the kernel where userspace can specify an arbitrary hash algorithm by name, and the kernel uses it as unkeyed hash without checking whether it is really unkeyed. Examples of this include:
- KEYCTL_DH_COMPUTE, via the KDF extension
- dm-verity
- dm-crypt, via the ESSIV support
- dm-integrity, via the "internal hash" mode with no key given
- drbd (Distributed Replicated Block Device)
This bug is especially bad for KEYCTL_DH_COMPUTE as that requires no privileges to call.
Fix the bug for all users by adding a flag CRYPTO_TFM_NEED_KEY to the ->crt_flags of each hash transform that indicates whether the transform still needs to be keyed or not. Then, make the hash init, import, and digest functions return -ENOKEY if the key is still needed.
The new flag also replaces the 'has_key' bool which algif_hash was previously using, thereby simplifying the algif_hash implementation.
--- crypto/ahash.c | 22 ++++++++++++++++---- crypto/algif_hash.c | 52 ++++++++++--------------------------------------- crypto/shash.c | 25 +++++++++++++++++++---- include/crypto/hash.h | 34 ++++++++++++++++++++++---------- include/linux/crypto.h | 2 + 5 files changed, 75 insertions(+), 60 deletions(-)
crypto/ahash.c +17 -5
@@ -193,11 +193,18 @@ int crypto_ahash_setkey(struct crypto_ah unsigned int keylen) {unsigned long alignmask =crypto_ahash_alignmask (tfm); +int err;if ((unsigned long )key & alignmask) -return ahash_setkey_unaligned (tfm, key, keylen); + err =ahash_setkey_unaligned (tfm, key, keylen); +else + err = tfm->setkey (tfm, key, keylen); + +if (err) +return err; -return tfm->setkey (tfm, key, keylen); +crypto_ahash_clear_flags (tfm,CRYPTO_TFM_NEED_KEY ); +return 0 ; }EXPORT_SYMBOL_GPL (crypto_ahash_setkey);
@@ -370,7 +377,12 @@ EXPORT_SYMBOL_GPL(crypto_ahash_finup);int crypto_ahash_digest (struct ahash_request *req) { -return crypto_ahash_op (req,crypto_ahash_reqtfm (req)->digest); +struct crypto_ahash *tfm =crypto_ahash_reqtfm (req); + +if (crypto_ahash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; + +return crypto_ahash_op (req, tfm->digest); }EXPORT_SYMBOL_GPL (crypto_ahash_digest);
@@ -456,7 +468,6 @@ static int crypto_ahash_init_tfm(structstruct ahash_alg *alg =crypto_ahash_alg (hash); hash->setkey = ahash_nosetkey; - hash->has_setkey = false; hash->export = ahash_no_export; hash->import = ahash_no_import;
@@ -471,7 +482,8 @@ static int crypto_ahash_init_tfm(structif (alg->setkey) { hash->setkey = alg->setkey; - hash->has_setkey = true; +if (!(alg->halg.base.cra_flags &CRYPTO_ALG_OPTIONAL_KEY )) +crypto_ahash_set_flags (hash,CRYPTO_TFM_NEED_KEY ); }if (alg->export) hash->export = alg->export;
crypto/algif_hash.c +11 -41
104 lines not on this page · raw message
crypto/shash.c +21 -4
@@ -58,11 +58,18 @@ int crypto_shash_setkey(struct crypto_sh {struct shash_alg *shash =crypto_shash_alg (tfm);unsigned long alignmask =crypto_shash_alignmask (tfm); +int err;if ((unsigned long )key & alignmask) -return shash_setkey_unaligned (tfm, key, keylen); + err =shash_setkey_unaligned (tfm, key, keylen); +else + err = shash->setkey (tfm, key, keylen); + +if (err) +return err; -return shash->setkey (tfm, key, keylen); +crypto_shash_clear_flags (tfm,CRYPTO_TFM_NEED_KEY ); +return 0 ; }EXPORT_SYMBOL_GPL (crypto_shash_setkey);
@@ -181,6 +188,9 @@ int crypto_shash_digest(struct shash_desstruct shash_alg *shash =crypto_shash_alg (tfm);unsigned long alignmask =crypto_shash_alignmask (tfm); +if (crypto_shash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; +if (((unsigned long )data | (unsigned long )out) & alignmask)return shash_digest_unaligned (desc, data, len, out);
@@ -360,7 +370,8 @@ int crypto_init_shash_ops_async(struct c crt->digest = shash_async_digest; crt->setkey = shash_async_setkey; - crt->has_setkey = alg->setkey != shash_no_setkey; +crypto_ahash_set_flags (crt,crypto_shash_get_flags (shash) & +CRYPTO_TFM_NEED_KEY );if (alg->export) crt->export = shash_async_export;
@@ -375,8 +386,14 @@ int crypto_init_shash_ops_async(struct cstatic int crypto_shash_init_tfm (struct crypto_tfm *tfm) {struct crypto_shash *hash =__crypto_shash_cast (tfm); +struct shash_alg *alg =crypto_shash_alg (hash); + + hash->descsize = alg->descsize; + +if (crypto_shash_alg_has_setkey (alg) && + !(alg->base.cra_flags &CRYPTO_ALG_OPTIONAL_KEY )) +crypto_shash_set_flags (hash,CRYPTO_TFM_NEED_KEY ); - hash->descsize =crypto_shash_alg (hash)->descsize;return 0 ; }
include/crypto/hash.h +24 -10
@@ -205,7 +205,6 @@ struct crypto_ahash { unsigned int keylen);unsigned int reqsize; -bool has_setkey;struct crypto_tfm base; };
@@ -405,11 +404,6 @@ static inline void *ahash_request_ctx(stint crypto_ahash_setkey (struct crypto_ahash *tfm,const u8 *key,unsigned int keylen); -static inline bool crypto_ahash_has_setkey (struct crypto_ahash *tfm) -{ -return tfm->has_setkey; -} -/** * crypto_ahash_finup() - update and finalize message digest * @req: reference to the ahash_request handle that holds all information
@@ -481,7 +475,12 @@ static inline int crypto_ahash_export(st*/ static inline int crypto_ahash_import (struct ahash_request *req,const void *in) { -return crypto_ahash_reqtfm (req)->import (req, in); +struct crypto_ahash *tfm =crypto_ahash_reqtfm (req); + +if (crypto_ahash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; + +return tfm->import (req, in); }/**
@@ -498,7 +497,12 @@ static inline int crypto_ahash_import(st*/ static inline int crypto_ahash_init (struct ahash_request *req) { -return crypto_ahash_reqtfm (req)->init (req); +struct crypto_ahash *tfm =crypto_ahash_reqtfm (req); + +if (crypto_ahash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; + +return tfm->init (req); }/**
@@ -851,7 +855,12 @@ static inline int crypto_shash_export(st*/ static inline int crypto_shash_import (struct shash_desc *desc,const void *in) { -return crypto_shash_alg (desc->tfm)->import (desc, in); +struct crypto_shash *tfm = desc->tfm; + +if (crypto_shash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; + +return crypto_shash_alg (tfm)->import (desc, in); }/**
@@ -867,7 +876,12 @@ static inline int crypto_shash_import(st*/ static inline int crypto_shash_init (struct shash_desc *desc) { -return crypto_shash_alg (desc->tfm)->init (desc); +struct crypto_shash *tfm = desc->tfm; + +if (crypto_shash_get_flags (tfm) &CRYPTO_TFM_NEED_KEY ) +return -ENOKEY ; + +return crypto_shash_alg (tfm)->init (desc); }/**
include/linux/crypto.h +2 -0
@@ -114,6 +114,8 @@/* * Transform masks and values (for crt_flags). */ +#define CRYPTO_TFM_NEED_KEY 0x00000001 +#define CRYPTO_TFM_REQ_MASK 0x000fff00#define CRYPTO_TFM_RES_MASK 0xfff00000
Patches currently in stable-queue which might be from [email protected] are
queue-4.14/crypto-hash-annotate-algorithms-taking-optional-key.patch queue-4.14/crypto-cryptd-pass-through-absence-of-setkey.patch queue-4.14/crypto-hash-prevent-using-keyed-hashes-without-setting-key.patch queue-4.14/ubifs-free-the-encrypted-symlink-target.patch queue-4.14/nfs-reject-request-for-id_legacy-key-without-auxdata.patch queue-4.14/crypto-poly1305-remove-setkey-method.patch queue-4.14/crypto-hash-introduce-crypto_hash_alg_has_setkey.patch queue-4.14/crypto-mcryptd-pass-through-absence-of-setkey.patch