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

This Linux kernel change "lib/scatterlist: Fix mapping iterator when sg->offset is greater than PAGE_SIZE" is included in the Linux 4.4.187 release. This change is authored by Christophe Leroy <christophe.leroy [at] c-s.fr> on Mon Jun 24 07:20:14 2019 +0000. The commit for this change in Linux stable tree is 2e85872 (patch) which is from upstream commit aeb8724. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream aeb8724.

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

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>

There are 9 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 lib/scatterlist.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index bafa993..0b86b79 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -496,17 +496,18 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
 {
    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);
    }

Leave a Reply

Your email address will not be published. Required fields are marked *