[RFC] crypto: ccree - protect against short scatterlists

From: Gilad Ben-Yossef
Date: Sun Jan 26 2020 - 08:38:27 EST


Deal gracefully with the event of being handed a scatterlist
which is shorter than expected.

This mitigates a crash in some cases of crashes due to
attempt to map empty (but not NULL) scatterlists with none
zero lengths.

This is an interim patch, to help diagnoze the issue, not
intended for mainline in its current form as of yet.

Signed-off-by: Gilad Ben-Yossef <gilad@xxxxxxxxxxxxx>
Reported-by: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
---
drivers/crypto/ccree/cc_buffer_mgr.c | 30 +++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/ccree/cc_buffer_mgr.c b/drivers/crypto/ccree/cc_buffer_mgr.c
index a72586eccd81..9667a2630c66 100644
--- a/drivers/crypto/ccree/cc_buffer_mgr.c
+++ b/drivers/crypto/ccree/cc_buffer_mgr.c
@@ -286,10 +286,32 @@ static void cc_add_sg_entry(struct device *dev, struct buffer_array *sgl_data,
sgl_data->num_of_buffers++;
}

+static unsigned int cc_sg_trunc_len(struct scatterlist *sg, unsigned int len)
+{
+ unsigned int total;
+
+ if (!len)
+ return 0;
+
+ for (total = 0; sg; sg = sg_next(sg)) {
+ total += sg->length;
+ if (total >= len) {
+ total = len;
+ break;
+ }
+ }
+
+ return total;
+}
+
static int cc_map_sg(struct device *dev, struct scatterlist *sg,
unsigned int nbytes, int direction, u32 *nents,
u32 max_sg_nents, u32 *lbytes, u32 *mapped_nents)
{
+ int ret;
+
+ nbytes = cc_sg_trunc_len(sg, nbytes);
+
if (sg_is_last(sg)) {
/* One entry only case -set to DLLI */
if (dma_map_sg(dev, sg, 1, direction) != 1) {
@@ -313,12 +335,14 @@ static int cc_map_sg(struct device *dev, struct scatterlist *sg,
/* In case of mmu the number of mapped nents might
* be changed from the original sgl nents
*/
- *mapped_nents = dma_map_sg(dev, sg, *nents, direction);
- if (*mapped_nents == 0) {
+ ret = dma_map_sg(dev, sg, *nents, direction);
+ if (dma_mapping_error(dev, ret)) {
*nents = 0;
- dev_err(dev, "dma_map_sg() sg buffer failed\n");
+ dev_err(dev, "dma_map_sg() sg buffer failed %d\n", ret);
return -ENOMEM;
}
+
+ *mapped_nents = ret;
}

return 0;
--
2.23.0