| From aeb87246537a83c2aff482f3f34a2e0991e02cbc Mon Sep 17 00:00:00 2001 |
| From: Christophe Leroy <christophe.leroy@c-s.fr> |
| Date: Mon, 24 Jun 2019 07:20:14 +0000 |
| Subject: lib/scatterlist: Fix mapping iterator when sg->offset is greater than PAGE_SIZE |
| |
| From: Christophe Leroy <christophe.leroy@c-s.fr> |
| |
| commit aeb87246537a83c2aff482f3f34a2e0991e02cbc upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| lib/scatterlist.c | 9 +++++---- |
| 1 file changed, 5 insertions(+), 4 deletions(-) |
| |
| --- a/lib/scatterlist.c |
| +++ b/lib/scatterlist.c |
| @@ -496,17 +496,18 @@ static bool sg_miter_get_next_page(struc |
| { |
| if (!miter->__remaining) { |
| struct scatterlist *sg; |
| - unsigned long pgoffset; |
| |
| if (!__sg_page_iter_next(&miter->piter)) |
| return false; |
| |
| sg = miter->piter.sg; |
| - pgoffset = miter->piter.sg_pgoffset; |
| |
| - miter->__offset = pgoffset ? 0 : sg->offset; |
| + miter->__offset = miter->piter.sg_pgoffset ? 0 : sg->offset; |
| + miter->piter.sg_pgoffset += miter->__offset >> PAGE_SHIFT; |
| + miter->__offset &= PAGE_SIZE - 1; |
| miter->__remaining = sg->offset + sg->length - |
| - (pgoffset << PAGE_SHIFT) - miter->__offset; |
| + (miter->piter.sg_pgoffset << PAGE_SHIFT) - |
| + miter->__offset; |
| miter->__remaining = min_t(unsigned long, miter->__remaining, |
| PAGE_SIZE - miter->__offset); |
| } |