diff options
author | Austin Shafer <ashafer@badland.io> | 2023-04-21 07:56:50 +0000 |
---|---|---|
committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2023-11-29 16:36:05 +0000 |
commit | 934b2489b951698adc5d4c3421fa66fb80be7052 (patch) | |
tree | d8680cd059646304c5bbc0f537a6a0faa31c77ab /sys/compat/linuxkpi/common/include/linux/scatterlist.h | |
parent | 88910886fa50a6eccdc7d263778143ddd68c61df (diff) | |
download | src-934b2489b951698adc5d4c3421fa66fb80be7052.tar.gz src-934b2489b951698adc5d4c3421fa66fb80be7052.zip |
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.
(cherry picked from commit 3f686532c9b4fd603d4ad2d3392232cff24188f4)
Commit 3f686532c9b4 tried to fix an issue with not properly starting
at the first page in the sg list to prevent a panic. This worked but
with the side effect of incrementing "s" during the final iteration
causing it to be NULL since the list had ended.
In cases non-DEBUG kernels this causes a panic with drm-5.15, since
"s" is NULL when we later pass it to sg_mark_end().
This change decouples the iteration sg from the return value so that
it is never incremented past the final page in the chain.
(cherry picked from commit 09b0401e91a92bcb58ea1873857b42f8211f660f)
Diffstat (limited to 'sys/compat/linuxkpi/common/include/linux/scatterlist.h')
-rw-r--r-- | sys/compat/linuxkpi/common/include/linux/scatterlist.h | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h index 17928f9c50e5..e462d5c649f1 100644 --- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h +++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h @@ -343,7 +343,7 @@ __sg_alloc_table_from_pages(struct sg_table *sgt, { unsigned int i, segs, cur, len; int rc; - struct scatterlist *s; + struct scatterlist *s, *sg_iter; #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300 if (prv != NULL) { @@ -377,11 +377,17 @@ __sg_alloc_table_from_pages(struct sg_table *sgt, #endif cur = 0; - for (i = 0, s = sgt->sgl; i < sgt->orig_nents; i++) { + for_each_sg(sgt->sgl, sg_iter, sgt->orig_nents, i) { unsigned long seg_size; unsigned int j; - s = sg_next(s); + /* + * We need to make sure that when we exit this loop "s" has the + * last sg in the chain so we can call sg_mark_end() on it. + * Only set this inside the loop since sg_iter will be iterated + * until it is NULL. + */ + s = sg_iter; len = 0; for (j = cur + 1; j < count; ++j) { |