Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <phx0fer@gmail.com>

Unset MAY_BACKLOG on the async completion path so the user won't
see back-to-back EINPROGRESS notifications.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Dudu Lu and committed by
Herbert Xu
3bfbf5f0 5aa58c3a

+31 -21
+31 -21
crypto/krb5enc.c
··· 39 39 char tail[]; 40 40 }; 41 41 42 - static void krb5enc_request_complete(struct aead_request *req, int err) 43 - { 44 - if (err != -EINPROGRESS) 45 - aead_request_complete(req, err); 46 - } 47 - 48 42 /** 49 43 * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob. 50 44 * @keys: Where to put the key sizes and pointers ··· 121 127 { 122 128 struct aead_request *req = data; 123 129 124 - krb5enc_request_complete(req, err); 130 + aead_request_complete(req, err); 125 131 } 126 132 127 133 /* ··· 182 188 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 183 189 184 190 if (err) 185 - return krb5enc_request_complete(req, err); 191 + goto out; 186 192 187 193 krb5enc_insert_checksum(req, ahreq->result); 188 194 189 - err = krb5enc_dispatch_encrypt(req, 190 - aead_request_flags(req) & ~CRYPTO_TFM_REQ_MAY_SLEEP); 191 - if (err != -EINPROGRESS) 192 - aead_request_complete(req, err); 195 + err = krb5enc_dispatch_encrypt(req, 0); 196 + if (err == -EINPROGRESS) 197 + return; 198 + 199 + out: 200 + aead_request_complete(req, err); 193 201 } 194 202 195 203 /* ··· 261 265 { 262 266 struct aead_request *req = data; 263 267 264 - if (err) 265 - return krb5enc_request_complete(req, err); 266 - 267 - err = krb5enc_verify_hash(req); 268 - krb5enc_request_complete(req, err); 268 + if (!err) 269 + err = krb5enc_verify_hash(req); 270 + aead_request_complete(req, err); 269 271 } 270 272 271 273 /* 272 274 * Dispatch the hashing of the plaintext after we've done the decryption. 273 275 */ 274 - static int krb5enc_dispatch_decrypt_hash(struct aead_request *req) 276 + static int krb5enc_dispatch_decrypt_hash(struct aead_request *req, 277 + unsigned int flags) 275 278 { 276 279 struct crypto_aead *krb5enc = crypto_aead_reqtfm(req); 277 280 struct aead_instance *inst = aead_alg_instance(krb5enc); ··· 286 291 ahash_request_set_tfm(ahreq, auth); 287 292 ahash_request_set_crypt(ahreq, req->dst, hash, 288 293 req->assoclen + req->cryptlen - authsize); 289 - ahash_request_set_callback(ahreq, aead_request_flags(req), 294 + ahash_request_set_callback(ahreq, flags, 290 295 krb5enc_decrypt_hash_done, req); 291 296 292 297 err = crypto_ahash_digest(ahreq); ··· 294 299 return err; 295 300 296 301 return krb5enc_verify_hash(req); 302 + } 303 + 304 + static void krb5enc_decrypt_done(void *data, int err) 305 + { 306 + struct aead_request *req = data; 307 + 308 + if (err) 309 + goto out; 310 + 311 + err = krb5enc_dispatch_decrypt_hash(req, 0); 312 + if (err == -EINPROGRESS) 313 + return; 314 + 315 + out: 316 + aead_request_complete(req, err); 297 317 } 298 318 299 319 /* ··· 334 324 335 325 skcipher_request_set_tfm(skreq, ctx->enc); 336 326 skcipher_request_set_callback(skreq, aead_request_flags(req), 337 - req->base.complete, req->base.data); 327 + krb5enc_decrypt_done, req); 338 328 skcipher_request_set_crypt(skreq, src, dst, 339 329 req->cryptlen - authsize, req->iv); 340 330 ··· 349 339 if (err < 0) 350 340 return err; 351 341 352 - return krb5enc_dispatch_decrypt_hash(req); 342 + return krb5enc_dispatch_decrypt_hash(req, aead_request_flags(req)); 353 343 } 354 344 355 345 static int krb5enc_init_tfm(struct crypto_aead *tfm)