Skip to content

Commit

Permalink
spi: use sg_next for walking through the allocated scatterlist table
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Juan Gutierrez authored and Mark Brown committed Nov 22, 2016
1 parent 1001354 commit 8dd4a01
Showing 1 changed file with 5 additions and 2 deletions.
7 changes: 5 additions & 2 deletions drivers/spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
int desc_len;
int sgs;
struct page *vm_page;
struct scatterlist *sg;
void *sg_buf;
size_t min;
int i, ret;
Expand All @@ -738,6 +739,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
if (ret != 0)
return ret;

sg = &sgt->sgl[0];
for (i = 0; i < sgs; i++) {

if (vmalloced_buf || kmap_buf) {
Expand All @@ -751,16 +753,17 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
sg_free_table(sgt);
return -ENOMEM;
}
sg_set_page(&sgt->sgl[i], vm_page,
sg_set_page(sg, vm_page,
min, offset_in_page(buf));
} else {
min = min_t(size_t, len, desc_len);
sg_buf = buf;
sg_set_buf(&sgt->sgl[i], sg_buf, min);
sg_set_buf(sg, sg_buf, min);
}

buf += min;
len -= min;
sg = sg_next(sg);
}

ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
Expand Down

0 comments on commit 8dd4a01

Please sign in to comment.