diff options
author | Eric Biggers <ebiggers@google.com> | 2019-02-01 02:51:41 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-02-08 02:30:08 -0500 |
commit | 77568e535af7c4f97eaef1e555bf0af83772456c (patch) | |
tree | 5ad037fe1e2edc8dee2d44c36afb2ea86f062280 /crypto/ahash.c | |
parent | 3af349639597fea582a93604734d717e59a0e223 (diff) |
crypto: ahash - fix another early termination in hash walk
Hash algorithms with an alignmask set, e.g. "xcbc(aes-aesni)" and
"michael_mic", fail the improved hash tests because they sometimes
produce the wrong digest. The bug is that in the case where a
scatterlist element crosses pages, not all the data is actually hashed
because the scatterlist walk terminates too early. This happens because
the 'nbytes' variable in crypto_hash_walk_done() is assigned the number
of bytes remaining in the page, then later interpreted as the number of
bytes remaining in the scatterlist element. Fix it.
Fixes: 900a081f6912 ("crypto: ahash - Fix early termination in hash walk")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/ahash.c')
-rw-r--r-- | crypto/ahash.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c index ca0d3e281fef..81e2767e2164 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c | |||
@@ -86,17 +86,17 @@ static int hash_walk_new_entry(struct crypto_hash_walk *walk) | |||
86 | int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) | 86 | int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) |
87 | { | 87 | { |
88 | unsigned int alignmask = walk->alignmask; | 88 | unsigned int alignmask = walk->alignmask; |
89 | unsigned int nbytes = walk->entrylen; | ||
90 | 89 | ||
91 | walk->data -= walk->offset; | 90 | walk->data -= walk->offset; |
92 | 91 | ||
93 | if (nbytes && walk->offset & alignmask && !err) { | 92 | if (walk->entrylen && (walk->offset & alignmask) && !err) { |
94 | walk->offset = ALIGN(walk->offset, alignmask + 1); | 93 | unsigned int nbytes; |
95 | nbytes = min(nbytes, | ||
96 | ((unsigned int)(PAGE_SIZE)) - walk->offset); | ||
97 | walk->entrylen -= nbytes; | ||
98 | 94 | ||
95 | walk->offset = ALIGN(walk->offset, alignmask + 1); | ||
96 | nbytes = min(walk->entrylen, | ||
97 | (unsigned int)(PAGE_SIZE - walk->offset)); | ||
99 | if (nbytes) { | 98 | if (nbytes) { |
99 | walk->entrylen -= nbytes; | ||
100 | walk->data += walk->offset; | 100 | walk->data += walk->offset; |
101 | return nbytes; | 101 | return nbytes; |
102 | } | 102 | } |
@@ -116,7 +116,7 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) | |||
116 | if (err) | 116 | if (err) |
117 | return err; | 117 | return err; |
118 | 118 | ||
119 | if (nbytes) { | 119 | if (walk->entrylen) { |
120 | walk->offset = 0; | 120 | walk->offset = 0; |
121 | walk->pg++; | 121 | walk->pg++; |
122 | return hash_walk_next(walk); | 122 | return hash_walk_next(walk); |