When supplied with an offset equal to PAGE_SIZE, the hash walk code returns zero, resulting in early termination and, in the observed scenario, memory corruption. This patch fixes it by clamping nbytes only when walk->offset is not at the PAGE_SIZE boundary. Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Eli Cooper <elicooper@xxxxxxx> --- crypto/ahash.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index 3a35d67de7d9..03cbe04c53b1 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -46,8 +46,11 @@ static int hash_walk_next(struct crypto_hash_walk *walk) { unsigned int alignmask = walk->alignmask; unsigned int offset = walk->offset; - unsigned int nbytes = min(walk->entrylen, - ((unsigned int)(PAGE_SIZE)) - offset); + unsigned int pagelen, nbytes = walk->entrylen; + + pagelen = ((unsigned int)(PAGE_SIZE)) - offset; + if (pagelen) + nbytes = min(nbytes, pagelen); if (walk->flags & CRYPTO_ALG_ASYNC) walk->data = kmap(walk->pg); @@ -86,7 +89,7 @@ static int hash_walk_new_entry(struct crypto_hash_walk *walk) int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) { unsigned int alignmask = walk->alignmask; - unsigned int nbytes = walk->entrylen; + unsigned int pagelen, nbytes = walk->entrylen; walk->data -= walk->offset; @@ -94,8 +97,9 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) walk->offset = ALIGN(walk->offset, alignmask + 1); walk->data += walk->offset; - nbytes = min(nbytes, - ((unsigned int)(PAGE_SIZE)) - walk->offset); + pagelen = ((unsigned int)(PAGE_SIZE)) - walk->offset; + if (pagelen) + nbytes = min(nbytes, pagelen); walk->entrylen -= nbytes; return nbytes; -- 2.16.2