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

lib/scatterlist: Fix mapping iterator when sg->offset is greater than PAGE_SIZE

All mapping iterator logic is based on the assumption that sg->offset
is always lower than PAGE_SIZE.

But there are situations where sg->offset is such that the SG item
is on the second page. In that case sg_copy_to_buffer() fails
properly copying the data into the buffer. One of the reason is
that the data will be outside the kmapped area used to access that
data.

This patch fixes the issue by adjusting the mapping iterator
offset and pgoffset fields such that offset is always lower than
PAGE_SIZE.

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Fixes: 4225fc8555a9 ("lib/scatterlist: use page iterator in the mapping iterator")
Cc: stable@vger.kernel.org
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Christophe Leroy and committed by
Herbert Xu
aeb87246 e52d484d

+5 -4
+5 -4
lib/scatterlist.c
··· 678 678 { 679 679 if (!miter->__remaining) { 680 680 struct scatterlist *sg; 681 - unsigned long pgoffset; 682 681 683 682 if (!__sg_page_iter_next(&miter->piter)) 684 683 return false; 685 684 686 685 sg = miter->piter.sg; 687 - pgoffset = miter->piter.sg_pgoffset; 688 686 689 - miter->__offset = pgoffset ? 0 : sg->offset; 687 + miter->__offset = miter->piter.sg_pgoffset ? 0 : sg->offset; 688 + miter->piter.sg_pgoffset += miter->__offset >> PAGE_SHIFT; 689 + miter->__offset &= PAGE_SIZE - 1; 690 690 miter->__remaining = sg->offset + sg->length - 691 - (pgoffset << PAGE_SHIFT) - miter->__offset; 691 + (miter->piter.sg_pgoffset << PAGE_SHIFT) - 692 + miter->__offset; 692 693 miter->__remaining = min_t(unsigned long, miter->__remaining, 693 694 PAGE_SIZE - miter->__offset); 694 695 }