crypto: krb5enc - fix async decrypt skipping hash verification
PATCH 1/1 crypto: krb5enc - fix async decrypt skipping hash verification
krb5enc_dispatch_decrypt() sets req->base.complete as the skcipher callback, which is the caller's own completion handler. When the skcipher completes asynchronously, this signals "done" to the caller without executing krb5enc_dispatch_decrypt_hash(), completely bypassing the integrity verification (hash check).
Compare with the encrypt path which correctly uses krb5enc_encrypt_done as an intermediate callback to chain into the hash computation on async completion.
Fix by adding krb5enc_decrypt_done as an intermediate callback that chains into krb5enc_dispatch_decrypt_hash() upon async skcipher completion, matching the encrypt path's callback pattern.
Also fix EBUSY/EINPROGRESS handling throughout: remove krb5enc_request_complete() which incorrectly swallowed EINPROGRESS notifications that must be passed up to callers waiting on backlogged requests, and add missing EBUSY checks in krb5enc_encrypt_ahash_done for the dispatch_encrypt return value.
--- crypto/krb5enc.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-)
crypto/krb5enc.c +26 -16
@@ -39,12 +39,6 @@ struct krb5enc_request_ctx {char tail[]; }; -static void krb5enc_request_complete (struct aead_request *req,int err) -{ -if (err != -EINPROGRESS ) -aead_request_complete (req, err); -} -/** * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob. * @keys: Where to put the key sizes and pointers
@@ -127,7 +121,7 @@ static void krb5enc_encrypt_done(void *data, int err) {struct aead_request *req = data; -krb5enc_request_complete (req, err); +aead_request_complete (req, err); }/*
@@ -188,13 +182,16 @@ static void krb5enc_encrypt_ahash_done(void *data, int err)struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);if (err) -return krb5enc_request_complete (req, err); + goto out;krb5enc_insert_checksum (req, ahreq->result); err =krb5enc_dispatch_encrypt (req,0 ); -if (err != -EINPROGRESS ) -aead_request_complete (req, err); +if (err == -EINPROGRESS || err == -EBUSY ) +return ; + +out: +aead_request_complete (req, err); }/*
@@ -264,11 +261,9 @@ static void krb5enc_decrypt_hash_done(void *data, int err) {struct aead_request *req = data; -if (err) -return krb5enc_request_complete (req, err); - - err =krb5enc_verify_hash (req); -krb5enc_request_complete (req, err); +if (!err) + err =krb5enc_verify_hash (req); +aead_request_complete (req, err); }/*
@@ -300,6 +295,21 @@ static int krb5enc_dispatch_decrypt_hash(struct aead_request *req)return krb5enc_verify_hash (req); } +static void krb5enc_decrypt_done (void *data,int err) +{ +struct aead_request *req = data; + +if (err) + goto out; + + err =krb5enc_dispatch_decrypt_hash (req); +if (err == -EINPROGRESS || err == -EBUSY ) +return ; + +out: +aead_request_complete (req, err); +} +/* * Dispatch the decryption of the ciphertext. */
@@ -323,7 +333,7 @@ static int krb5enc_dispatch_decrypt(struct aead_request *req)skcipher_request_set_tfm (skreq, ctx->enc);skcipher_request_set_callback (skreq,aead_request_flags (req), - req->base.complete, req->base.data); + krb5enc_decrypt_done, req);skcipher_request_set_crypt (skreq, src, dst, req->cryptlen - authsize, req->iv);
Signature · 1 line
2.39.3 (Apple Git-145)
Herbert Xu
maintainerQuoted 20 lines · Dudu Lu
krb5enc_dispatch_decrypt()setsreq->base.completeas the skcipher callback, which is the caller's own completion handler. When the skcipher completes asynchronously, this signals "done" to the caller without executingkrb5enc_dispatch_decrypt_hash(), completely bypassing the integrity verification (hash check).Compare with the encrypt path which correctly uses
krb5enc_encrypt_doneas an intermediate callback to chain into the hash computation on async completion.Fix by adding
krb5enc_decrypt_doneas an intermediate callback that chains intokrb5enc_dispatch_decrypt_hash()upon async skcipher completion, matching the encrypt path's callback pattern.Also fix EBUSY/EINPROGRESS handling throughout: remove
krb5enc_request_complete()which incorrectly swallowed EINPROGRESS notifications that must be passed up to callers waiting on backlogged requests, and add missing EBUSY checks inkrb5enc_encrypt_ahash_donefor thedispatch_encryptreturn value.
Quoted 5 lines
Fixes d1775a177f7f ("crypto: Add 'krb5enc' hash and cipher AEAD algorithm")Signed-off-by Dudu Lu <[email protected]>--- crypto/krb5enc.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-)
Thanks. Your patch looks good to me.
However, while applying it against mainline I got a conflict because of the recent change to unset the MAY_SLEEP flag on the async completion path.
That got me thinking and I found one more issue, if we try to do a MAY_BACKLOG operation on the async completion path, then the user will see two back-to-back EINPROGRESS notifications which is wrong.
As David still hasn't indicated his preference to whether MAY_BACKLOG should be supported or not, I've taken the easy option and simply disallowed MAY_BACKLOG on the async completion path. In order to support it, you need to add a flag to the request context so that the second EINPROGRESS notification can be selectively filtered out.
So this is what I ended up applying:
commit b51261043f3b6863ed4b65ccad967d998cd302f5
Author: Dudu Lu <[email protected]> Date: Mon Apr 20 12:40:27 2026 +0800
crypto: krb5enc - fix async decrypt skipping hash verification
krb5enc_dispatch_decrypt() sets req->base.complete as the skcipher callback, which is the caller's own completion handler. When the skcipher completes asynchronously, this signals "done" to the caller without executing krb5enc_dispatch_decrypt_hash(), completely bypassing the integrity verification (hash check).
Compare with the encrypt path which correctly uses krb5enc_encrypt_done as an intermediate callback to chain into the hash computation on async completion.
Fix by adding krb5enc_decrypt_done as an intermediate callback that chains into krb5enc_dispatch_decrypt_hash() upon async skcipher completion, matching the encrypt path's callback pattern.
Also fix EBUSY/EINPROGRESS handling throughout: remove krb5enc_request_complete() which incorrectly swallowed EINPROGRESS notifications that must be passed up to callers waiting on backlogged requests, and add missing EBUSY checks in krb5enc_encrypt_ahash_done for the dispatch_encrypt return value.
Unset MAY_BACKLOG on the async completion path so the user won't see back-to-back EINPROGRESS notifications.
crypto/krb5enc.c +31 -21
@@ -39,12 +39,6 @@ struct krb5enc_request_ctx {char tail[]; }; -static void krb5enc_request_complete (struct aead_request *req,int err) -{ -if (err != -EINPROGRESS ) -aead_request_complete (req, err); -} -/** * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob. * @keys: Where to put the key sizes and pointers
@@ -127,7 +121,7 @@ static void krb5enc_encrypt_done(void *data, int err) {struct aead_request *req = data; -krb5enc_request_complete (req, err); +aead_request_complete (req, err); }/*
@@ -188,14 +182,16 @@ static void krb5enc_encrypt_ahash_done(void *data, int err)struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);if (err) -return krb5enc_request_complete (req, err); + goto out;krb5enc_insert_checksum (req, ahreq->result); - err =krb5enc_dispatch_encrypt (req, -aead_request_flags (req) & ~CRYPTO_TFM_REQ_MAY_SLEEP ); -if (err != -EINPROGRESS ) -aead_request_complete (req, err); + err =krb5enc_dispatch_encrypt (req,0 ); +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); }/*
@@ -265,17 +261,16 @@ static void krb5enc_decrypt_hash_done(void *data, int err) {struct aead_request *req = data; -if (err) -return krb5enc_request_complete (req, err); - - err =krb5enc_verify_hash (req); -krb5enc_request_complete (req, err); +if (!err) + err =krb5enc_verify_hash (req); +aead_request_complete (req, err); }/* * Dispatch the hashing of the plaintext after we've done the decryption. */ -static int krb5enc_dispatch_decrypt_hash (struct aead_request *req) +static int krb5enc_dispatch_decrypt_hash (struct aead_request *req, +unsigned int flags) {struct crypto_aead *krb5enc =crypto_aead_reqtfm (req);struct aead_instance *inst =aead_alg_instance (krb5enc);
@@ -291,7 +286,7 @@ static int krb5enc_dispatch_decrypt_hash(struct aead_request *req)ahash_request_set_tfm (ahreq, auth);ahash_request_set_crypt (ahreq, req->dst, hash, req->assoclen + req->cryptlen - authsize); -ahash_request_set_callback (ahreq,aead_request_flags (req), +ahash_request_set_callback (ahreq, flags, krb5enc_decrypt_hash_done, req); err =crypto_ahash_digest (ahreq);
@@ -301,6 +296,21 @@ static int krb5enc_dispatch_decrypt_hash(struct aead_request *req)return krb5enc_verify_hash (req); } +static void krb5enc_decrypt_done (void *data,int err) +{ +struct aead_request *req = data; + +if (err) + goto out; + + err =krb5enc_dispatch_decrypt_hash (req,0 ); +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); +} +/* * Dispatch the decryption of the ciphertext. */
@@ -324,7 +334,7 @@ static int krb5enc_dispatch_decrypt(struct aead_request *req)skcipher_request_set_tfm (skreq, ctx->enc);skcipher_request_set_callback (skreq,aead_request_flags (req), - req->base.complete, req->base.data); + krb5enc_decrypt_done, req);skcipher_request_set_crypt (skreq, src, dst, req->cryptlen - authsize, req->iv);
@@ -339,7 +349,7 @@ static int krb5enc_decrypt(struct aead_request *req)if (err <0 )return err; -return krb5enc_dispatch_decrypt_hash (req); +return krb5enc_dispatch_decrypt_hash (req,aead_request_flags (req)); }static int krb5enc_init_tfm (struct crypto_aead *tfm)
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt