From 3bfbf5f0a99c991769ec562721285df7ab69240b Mon Sep 17 00:00:00 2001 From: Dudu Lu Date: Mon, 20 Apr 2026 12:40:27 +0800 Subject: [PATCH] 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. Fixes: d1775a177f7f ("crypto: Add 'krb5enc' hash and cipher AEAD algorithm") Signed-off-by: Dudu Lu Unset MAY_BACKLOG on the async completion path so the user won't see back-to-back EINPROGRESS notifications. Signed-off-by: Herbert Xu --- crypto/krb5enc.c | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/crypto/krb5enc.c b/crypto/krb5enc.c index 1bfe8370cf94..fefa8d2c7532 100644 --- a/crypto/krb5enc.c +++ b/crypto/krb5enc.c @@ -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)