Re: [RFC] crypto: ccree - protect against short scatterlists

From: Geert Uytterhoeven
Date: Mon Jan 27 2020 - 03:03:34 EST


Hi Gilad,

On Sun, Jan 26, 2020 at 2:38 PM Gilad Ben-Yossef <gilad@xxxxxxxxxxxxx> wrote:
> 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>

Thanks for your patch!

Unfortunately this doesn't make a difference, as ...

> --- 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)) {

(1) this branch is taken, and not the else below,
(2) nothing acts upon detecting nbytes = 0.

With extra debug print:

cc_map_sg: nbytes = 0, first branch taken

> /* 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;

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds