[PATCH v2] crypto: ahash - Fix early termination in hash walk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Mar 25, 2018 at 11:49:58PM +0800, Eli Cooper wrote:
> 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);

hash_walk_next is only called from two places, neither of which
can produce an offset which is >= PAGE_SIZE.

> @@ -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;

Thanks, this bug is real.  However, the fix is still wrong.  What
happens is that we have just done the unaligned bit in the SG list
and now the page has been consumed.  We should not return directly
in this case but move onto the next page.

---8<--
When we have an unaligned SG list entry where there is no leftover
aligned data, the hash walk code will incorrectly return zero as if
the entire SG list has been processed.

This patch fixes it by moving onto the next page instead.

Reported-by: Eli Cooper <elicooper@xxxxxxx>
Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>

diff --git a/crypto/ahash.c b/crypto/ahash.c
index f732dd9..a64c143 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -92,13 +92,14 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
 
 	if (nbytes && walk->offset & alignmask && !err) {
 		walk->offset = ALIGN(walk->offset, alignmask + 1);
-		walk->data += walk->offset;
-
 		nbytes = min(nbytes,
 			     ((unsigned int)(PAGE_SIZE)) - walk->offset);
 		walk->entrylen -= nbytes;
 
-		return nbytes;
+		if (nbytes) {
+			walk->data += walk->offset;
+			return nbytes;
+		}
 	}
 
 	if (walk->flags & CRYPTO_ALG_ASYNC)
-- 
Email: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux