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: sta...@vger.kernel.org
Signed-off-by: Eli Cooper <elicoo...@gmx.com>
---
 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

Reply via email to