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

spi: use sg_next for walking through the allocated scatterlist table

A null dereference or Oops exception might occurs when reading at once the
whole content of an spi-nor of big enough size that requires an scatterlist
table that does not fit into one single page.

The spi_map_buf function is ignoring the chained sg case by dereferenceing
the scatterlist elements in an array fashion. This wrongly assumes that
the allocation of the scatterlist elements are contiguous. This is true as
long as the scatterlist table fits within a PAGE_SIZE. However, for
allocation where the scatter table is bigger than that, the pages allocated
by sg_alloc might not be contigous.

The sg table can be properly walked by sg_next instead of using an array.

Signed-off-by: Juan Gutierrez <juan.gutierrez@nxp.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Juan Gutierrez and committed by
Mark Brown
8dd4a016 1001354c

+5 -2
+5 -2
drivers/spi/spi.c
··· 720 720 int desc_len; 721 721 int sgs; 722 722 struct page *vm_page; 723 + struct scatterlist *sg; 723 724 void *sg_buf; 724 725 size_t min; 725 726 int i, ret; ··· 739 738 if (ret != 0) 740 739 return ret; 741 740 741 + sg = &sgt->sgl[0]; 742 742 for (i = 0; i < sgs; i++) { 743 743 744 744 if (vmalloced_buf || kmap_buf) { ··· 753 751 sg_free_table(sgt); 754 752 return -ENOMEM; 755 753 } 756 - sg_set_page(&sgt->sgl[i], vm_page, 754 + sg_set_page(sg, vm_page, 757 755 min, offset_in_page(buf)); 758 756 } else { 759 757 min = min_t(size_t, len, desc_len); 760 758 sg_buf = buf; 761 - sg_set_buf(&sgt->sgl[i], sg_buf, min); 759 + sg_set_buf(sg, sg_buf, min); 762 760 } 763 761 764 762 buf += min; 765 763 len -= min; 764 + sg = sg_next(sg); 766 765 } 767 766 768 767 ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);