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

Configure Feed

Select the types of activity you want to include in your feed.

crypto: hash - Fix test underflow in shash_ahash_digest

The test on PAGE_SIZE - offset in shash_ahash_digest can underflow,
leading to execution of the fast path even if the data cannot be
mapped into a single page.

Fix this by splitting the test into four cases:

1) nbytes > sg->length: More than one SG entry, slow path.
2) !IS_ENABLED(CONFIG_HIGHMEM): fast path.
3) nbytes > (unsigned int)PAGE_SIZE - offset: Two highmem pages, slow path.
4) Highmem fast path.

Fixes: 5f7082ed4f48 ("crypto: hash - Export shash through hash")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+26 -14
+26 -14
crypto/ahash.c
··· 16 16 #include <linux/cryptouser.h> 17 17 #include <linux/err.h> 18 18 #include <linux/kernel.h> 19 + #include <linux/mm.h> 19 20 #include <linux/module.h> 20 21 #include <linux/sched.h> 21 22 #include <linux/slab.h> ··· 202 201 unsigned int nbytes = req->nbytes; 203 202 struct scatterlist *sg; 204 203 unsigned int offset; 204 + struct page *page; 205 + const u8 *data; 205 206 int err; 206 207 207 - if (ahash_request_isvirt(req)) 208 - return crypto_shash_digest(desc, req->svirt, nbytes, 209 - req->result); 208 + data = req->svirt; 209 + if (!nbytes || ahash_request_isvirt(req)) 210 + return crypto_shash_digest(desc, data, nbytes, req->result); 210 211 211 - if (nbytes && 212 - (sg = req->src, offset = sg->offset, 213 - nbytes <= min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) { 214 - void *data; 212 + sg = req->src; 213 + if (nbytes > sg->length) 214 + return crypto_shash_init(desc) ?: 215 + shash_ahash_finup(req, desc); 215 216 216 - data = kmap_local_page(sg_page(sg)); 217 - err = crypto_shash_digest(desc, data + offset, nbytes, 218 - req->result); 219 - kunmap_local(data); 220 - } else 221 - err = crypto_shash_init(desc) ?: 222 - shash_ahash_finup(req, desc); 217 + page = sg_page(sg); 218 + offset = sg->offset; 219 + data = lowmem_page_address(page) + offset; 220 + if (!IS_ENABLED(CONFIG_HIGHMEM)) 221 + return crypto_shash_digest(desc, data, nbytes, req->result); 223 222 223 + page += offset >> PAGE_SHIFT; 224 + offset = offset_in_page(offset); 225 + 226 + if (nbytes > (unsigned int)PAGE_SIZE - offset) 227 + return crypto_shash_init(desc) ?: 228 + shash_ahash_finup(req, desc); 229 + 230 + data = kmap_local_page(page); 231 + err = crypto_shash_digest(desc, data + offset, nbytes, 232 + req->result); 233 + kunmap_local(data); 224 234 return err; 225 235 } 226 236 EXPORT_SYMBOL_GPL(shash_ahash_digest);