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

crypto: ahash - Fix EINPROGRESS notification callback

The ahash API modifies the request's callback function in order
to clean up after itself in some corner cases (unaligned final
and missing finup).

When the request is complete ahash will restore the original
callback and everything is fine. However, when the request gets
an EBUSY on a full queue, an EINPROGRESS callback is made while
the request is still ongoing.

In this case the ahash API will incorrectly call its own callback.

This patch fixes the problem by creating a temporary request
object on the stack which is used to relay EINPROGRESS back to
the original completion function.

This patch also adds code to preserve the original flags value.

Fixes: ab6bf4e5e5e4 ("crypto: hash - Fix the pointer voodoo in...")
Cc: <stable@vger.kernel.org>
Reported-by: Sabrina Dubroca <sd@queasysnail.net>
Tested-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+61 -30
+51 -30
crypto/ahash.c
··· 32 32 crypto_completion_t complete; 33 33 void *data; 34 34 u8 *result; 35 + u32 flags; 35 36 void *ubuf[] CRYPTO_MINALIGN_ATTR; 36 37 }; 37 38 ··· 254 253 priv->result = req->result; 255 254 priv->complete = req->base.complete; 256 255 priv->data = req->base.data; 256 + priv->flags = req->base.flags; 257 + 257 258 /* 258 259 * WARNING: We do not backup req->priv here! The req->priv 259 260 * is for internal use of the Crypto API and the ··· 270 267 return 0; 271 268 } 272 269 273 - static void ahash_restore_req(struct ahash_request *req) 270 + static void ahash_restore_req(struct ahash_request *req, int err) 274 271 { 275 272 struct ahash_request_priv *priv = req->priv; 276 273 274 + if (!err) 275 + memcpy(priv->result, req->result, 276 + crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 277 + 277 278 /* Restore the original crypto request. */ 278 279 req->result = priv->result; 279 - req->base.complete = priv->complete; 280 - req->base.data = priv->data; 280 + 281 + ahash_request_set_callback(req, priv->flags, 282 + priv->complete, priv->data); 281 283 req->priv = NULL; 282 284 283 285 /* Free the req->priv.priv from the ADJUSTED request. */ 284 286 kzfree(priv); 285 287 } 286 288 287 - static void ahash_op_unaligned_finish(struct ahash_request *req, int err) 289 + static void ahash_notify_einprogress(struct ahash_request *req) 288 290 { 289 291 struct ahash_request_priv *priv = req->priv; 292 + struct crypto_async_request oreq; 290 293 291 - if (err == -EINPROGRESS) 292 - return; 294 + oreq.data = priv->data; 293 295 294 - if (!err) 295 - memcpy(priv->result, req->result, 296 - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 297 - 298 - ahash_restore_req(req); 296 + priv->complete(&oreq, -EINPROGRESS); 299 297 } 300 298 301 299 static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) 302 300 { 303 301 struct ahash_request *areq = req->data; 302 + 303 + if (err == -EINPROGRESS) { 304 + ahash_notify_einprogress(areq); 305 + return; 306 + } 304 307 305 308 /* 306 309 * Restore the original request, see ahash_op_unaligned() for what ··· 318 309 */ 319 310 320 311 /* First copy req->result into req->priv.result */ 321 - ahash_op_unaligned_finish(areq, err); 312 + ahash_restore_req(areq, err); 322 313 323 314 /* Complete the ORIGINAL request. */ 324 315 areq->base.complete(&areq->base, err); ··· 334 325 return err; 335 326 336 327 err = op(req); 337 - ahash_op_unaligned_finish(req, err); 328 + if (err == -EINPROGRESS || 329 + (err == -EBUSY && (ahash_request_flags(req) & 330 + CRYPTO_TFM_REQ_MAY_BACKLOG))) 331 + return err; 332 + 333 + ahash_restore_req(req, err); 338 334 339 335 return err; 340 336 } ··· 374 360 } 375 361 EXPORT_SYMBOL_GPL(crypto_ahash_digest); 376 362 377 - static void ahash_def_finup_finish2(struct ahash_request *req, int err) 378 - { 379 - struct ahash_request_priv *priv = req->priv; 380 - 381 - if (err == -EINPROGRESS) 382 - return; 383 - 384 - if (!err) 385 - memcpy(priv->result, req->result, 386 - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); 387 - 388 - ahash_restore_req(req); 389 - } 390 - 391 363 static void ahash_def_finup_done2(struct crypto_async_request *req, int err) 392 364 { 393 365 struct ahash_request *areq = req->data; 394 366 395 - ahash_def_finup_finish2(areq, err); 367 + if (err == -EINPROGRESS) 368 + return; 369 + 370 + ahash_restore_req(areq, err); 396 371 397 372 areq->base.complete(&areq->base, err); 398 373 } ··· 392 389 goto out; 393 390 394 391 req->base.complete = ahash_def_finup_done2; 395 - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 392 + 396 393 err = crypto_ahash_reqtfm(req)->final(req); 394 + if (err == -EINPROGRESS || 395 + (err == -EBUSY && (ahash_request_flags(req) & 396 + CRYPTO_TFM_REQ_MAY_BACKLOG))) 397 + return err; 397 398 398 399 out: 399 - ahash_def_finup_finish2(req, err); 400 + ahash_restore_req(req, err); 400 401 return err; 401 402 } 402 403 ··· 408 401 { 409 402 struct ahash_request *areq = req->data; 410 403 404 + if (err == -EINPROGRESS) { 405 + ahash_notify_einprogress(areq); 406 + return; 407 + } 408 + 409 + areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 410 + 411 411 err = ahash_def_finup_finish1(areq, err); 412 + if (areq->priv) 413 + return; 412 414 413 415 areq->base.complete(&areq->base, err); 414 416 } ··· 432 416 return err; 433 417 434 418 err = tfm->update(req); 419 + if (err == -EINPROGRESS || 420 + (err == -EBUSY && (ahash_request_flags(req) & 421 + CRYPTO_TFM_REQ_MAY_BACKLOG))) 422 + return err; 423 + 435 424 return ahash_def_finup_finish1(req, err); 436 425 } 437 426
+10
include/crypto/internal/hash.h
··· 166 166 return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); 167 167 } 168 168 169 + static inline void ahash_request_complete(struct ahash_request *req, int err) 170 + { 171 + req->base.complete(&req->base, err); 172 + } 173 + 174 + static inline u32 ahash_request_flags(struct ahash_request *req) 175 + { 176 + return req->base.flags; 177 + } 178 + 169 179 static inline struct crypto_ahash *crypto_spawn_ahash( 170 180 struct crypto_ahash_spawn *spawn) 171 181 {