git: 3f686532c9b4 - main - linuxkpi: Fix __sg_alloc_table_from_pages loop

From: Emmanuel Vadot <manu_at_FreeBSD.org>
Date: Fri, 21 Apr 2023 07:58:11 UTC
The branch main has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=3f686532c9b4fd603d4ad2d3392232cff24188f4

commit 3f686532c9b4fd603d4ad2d3392232cff24188f4
Author:     Austin Shafer <ashafer@badland.io>
AuthorDate: 2023-04-21 07:56:50 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2023-04-21 07:56:50 +0000

    linuxkpi: Fix __sg_alloc_table_from_pages loop
    
    Commit 3e0856b63fe0e375a0951e05c2ef98bb2ebd9421 updated
    __sg_alloc_table_from_pages to use the same API as linux, but modified
    the loop condition when going over the pages in a sg list. Part of the
    change included moving the sg_next call out of the for loop and into the
    body, which causes an off by one error when traversing the list. Since
    sg_next is called before the loop body it will skip the first element
    and read one past the last element.
    
    This caused panics when running PRIME with nvidia-drm as the off-by-one
    issue causes a NULL dereference.
    
    Reviewed by:    bz, hselasky
    Differential Revision:  https://reviews.freebsd.org/D39628
    Fixes:  3e0856b63fe0 ("linuxkpi: Fix `sg_alloc_table_from_pages()` to have the same API as Linux")
---
 sys/compat/linuxkpi/common/include/linux/scatterlist.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
index fe4bce06819d..b448262f3497 100644
--- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -383,8 +383,6 @@ __sg_alloc_table_from_pages(struct sg_table *sgt,
 		unsigned long seg_size;
 		unsigned int j;
 
-		s = sg_next(s);
-
 		len = 0;
 		for (j = cur + 1; j < count; ++j) {
 			len += PAGE_SIZE;
@@ -398,6 +396,8 @@ __sg_alloc_table_from_pages(struct sg_table *sgt,
 		size -= seg_size;
 		off = 0;
 		cur = j;
+
+		s = sg_next(s);
 	}
 	KASSERT(s != NULL, ("s is NULL after loop in __sg_alloc_table_from_pages()"));