* [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest
@ 2026-09-30 11:35 Sebastian Brzezinka
2026-09-30 11:46 ` sashiko-bot
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Sebastian Brzezinka @ 2026-09-30 11:35 UTC (permalink / raw)
To: intel-gfx
Cc: Sebastian Brzezinka, andi.shyti, krzysztof.karas,
krzysztof.niemiec, chris.p.wilson
_igt_reset_stolen() use via __drm_mm_interval_first(), but
does so without holding i915->mm.stolen_lock. Every writer of this
(i915_gem_stolen.c: drm_mm_insert_node_in_range(), drm_mm_reserve_node(),
drm_mm_remove_node()) takes stolen_lock, so the selftest's unlocked
reader can race.
This was observed as a NULL pointer dereference in
__drm_mm_interval_first() during igt_reset_device_stolen():
BUG: kernel NULL pointer dereference, address: 0000000000000010
...
RIP: 0010:__drm_mm_interval_first+0x2c/0x90
...
Call Trace:
__igt_reset_stolen+0x565/0x6a0 [i915]
igt_reset_device_stolen+0x1a/0x30 [i915]
__i915_subtests+0xb8/0x250 [i915]
...
Also cap num_pages to i915->dsm.usable_size, which already excludes the
hardware reserved region from drm_mm.stolen's range, so poison/verify
writes never touch reserved stolen pages.
Fixes: 3da3c5c1c982 ("drm/i915: Exclude low pages (128KiB) of stolen from use")
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16841
Signed-off-by: Sebastian Brzezinka <sebastian.brzezinka@intel.com>
---
v1 -> v2:
- Fix always false !__drm_mm_interval_first() check (Andi)
- Extend stolen_lock over the poison/verify writes, not just
the lookup (Andi)
- Move the lookup into stolen_page_unused() helper
v2 -> v3:
- Cap num_pages to i915->dsm.usable_size to avoid poisoning
hardware reserved stolen pages (Shashiko)
---
drivers/gpu/drm/i915/gt/selftest_reset.c | 26 ++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c
index 2cfc23c58e90..811ddf991cb2 100644
--- a/drivers/gpu/drm/i915/gt/selftest_reset.c
+++ b/drivers/gpu/drm/i915/gt/selftest_reset.c
@@ -14,6 +14,16 @@
#include "selftests/igt_atomic.h"
#include "selftests/igt_spinner.h"
+static bool stolen_page_unused(struct intel_gt *gt, resource_size_t page)
+{
+ lockdep_assert_held(>->i915->mm.stolen_lock);
+
+ return __drm_mm_interval_first(>->i915->mm.stolen,
+ page << PAGE_SHIFT,
+ ((page + 1) << PAGE_SHIFT) - 1) ==
+ >->i915->mm.stolen.head_node;
+}
+
static int
__igt_reset_stolen(struct intel_gt *gt,
intel_engine_mask_t mask,
@@ -34,7 +44,8 @@ __igt_reset_stolen(struct intel_gt *gt,
if (!drm_mm_node_allocated(&ggtt->error_capture))
return 0;
- num_pages = resource_size(dsm) >> PAGE_SHIFT;
+ num_pages = min_t(resource_size_t, resource_size(dsm),
+ gt->i915->dsm.usable_size) >> PAGE_SHIFT;
if (!num_pages)
return 0;
@@ -95,10 +106,10 @@ __igt_reset_stolen(struct intel_gt *gt,
ggtt->error_capture.start,
PAGE_SIZE);
- if (!__drm_mm_interval_first(>->i915->mm.stolen,
- page << PAGE_SHIFT,
- ((page + 1) << PAGE_SHIFT) - 1))
+ mutex_lock(>->i915->mm.stolen_lock);
+ if (stolen_page_unused(gt, page))
memset_io(s, STACK_MAGIC, PAGE_SIZE);
+ mutex_unlock(>->i915->mm.stolen_lock);
in = (void __force *)s;
if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
@@ -143,16 +154,15 @@ __igt_reset_stolen(struct intel_gt *gt,
in = tmp;
x = crc32_le(0, in, PAGE_SIZE);
- if (x != crc[page] &&
- !__drm_mm_interval_first(>->i915->mm.stolen,
- page << PAGE_SHIFT,
- ((page + 1) << PAGE_SHIFT) - 1)) {
+ mutex_lock(>->i915->mm.stolen_lock);
+ if (x != crc[page] && stolen_page_unused(gt, page)) {
pr_debug("unused stolen page %pa modified by GPU reset\n",
&page);
if (count++ == 0)
igt_hexdump(in, PAGE_SIZE);
max = page;
}
+ mutex_unlock(>->i915->mm.stolen_lock);
io_mapping_unmap(s);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest
2026-09-30 11:35 [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Sebastian Brzezinka
@ 2026-09-30 11:46 ` sashiko-bot
2026-09-30 13:22 ` ✗ i915.CI.BAT: failure for drm/i915/selftests: Fix unlocked mm.stolen in reset selftest (rev5) Patchwork
2026-10-01 7:14 ` [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Krzysztof Karas
2 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-09-30 11:46 UTC (permalink / raw)
To: Sebastian Brzezinka; +Cc: intel-gfx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] selftests: TOCTOU race in unused stolen memory verification
--
commit c306e84112aa79cbd3009b777df94536525c83b4
Author: Sebastian Brzezinka <sebastian.brzezinka@intel.com>
drm/i915/selftests: Fix unlocked mm.stolen in reset selftest
This commit fixes an unlocked mm.stolen read by introducing the
stolen_page_unused() helper and wrapping accesses with stolen_lock. It also
caps num_pages to avoid the hardware-reserved region.
> diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c
> index 2cfc23c58e909..811ddf991cb27 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_reset.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c
[ ... ]
> @@ -95,10 +106,10 @@ __igt_reset_stolen(struct intel_gt *gt,
> ggtt->error_capture.start,
> PAGE_SIZE);
>
> - if (!__drm_mm_interval_first(>->i915->mm.stolen,
> - page << PAGE_SHIFT,
> - ((page + 1) << PAGE_SHIFT) - 1))
> + mutex_lock(>->i915->mm.stolen_lock);
> + if (stolen_page_unused(gt, page))
> memset_io(s, STACK_MAGIC, PAGE_SIZE);
> + mutex_unlock(>->i915->mm.stolen_lock);
>
> in = (void __force *)s;
> if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
> in = tmp;
> crc[page] = crc32_le(0, in, PAGE_SIZE);
[Severity: Medium]
Since stolen_lock is dropped before computing the CRC, does this introduce a
race window where a concurrent thread can allocate the page and modify it
before the initial CRC is calculated?
[ ... ]
> @@ -143,16 +154,15 @@ __igt_reset_stolen(struct intel_gt *gt,
> in = tmp;
> x = crc32_le(0, in, PAGE_SIZE);
>
> - if (x != crc[page] &&
> - !__drm_mm_interval_first(>->i915->mm.stolen,
> - page << PAGE_SHIFT,
> - ((page + 1) << PAGE_SHIFT) - 1)) {
> + mutex_lock(>->i915->mm.stolen_lock);
> + if (x != crc[page] && stolen_page_unused(gt, page)) {
[Severity: Medium]
Similarly, can a concurrent thread legitimately allocate, modify, and free the
page while the lock is dropped here?
If this happens, when stolen_lock is re-acquired, stolen_page_unused() will
return true, but the CRC will mismatch. Could this lead the test to falsely
report that the GPU reset clobbered unused stolen memory?
> pr_debug("unused stolen page %pa modified by GPU reset\n",
> &page);
> if (count++ == 0)
> igt_hexdump(in, PAGE_SIZE);
> max = page;
> }
> + mutex_unlock(>->i915->mm.stolen_lock);
>
> io_mapping_unmap(s);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260930113513.15169-1-sebastian.brzezinka@intel.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread* ✗ i915.CI.BAT: failure for drm/i915/selftests: Fix unlocked mm.stolen in reset selftest (rev5)
2026-09-30 11:35 [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Sebastian Brzezinka
2026-09-30 11:46 ` sashiko-bot
@ 2026-09-30 13:22 ` Patchwork
2026-10-01 7:14 ` [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Krzysztof Karas
2 siblings, 0 replies; 4+ messages in thread
From: Patchwork @ 2026-09-30 13:22 UTC (permalink / raw)
To: Sebastian Brzezinka; +Cc: intel-gfx
[-- Attachment #1: Type: text/plain, Size: 2538 bytes --]
== Series Details ==
Series: drm/i915/selftests: Fix unlocked mm.stolen in reset selftest (rev5)
URL : https://patchwork.freedesktop.org/series/172573/
State : failure
== Summary ==
CI Bug Log - changes from CI_DRM_19242 -> Patchwork_172573v5
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with Patchwork_172573v5 absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in Patchwork_172573v5, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
to document this new failure mode, which will reduce false positives in CI.
External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_172573v5/index.html
Participating hosts (39 -> 38)
------------------------------
Missing (1): bat-dg2-13
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in Patchwork_172573v5:
### IGT changes ###
#### Possible regressions ####
* igt@i915_selftest@live:
- fi-glk-j4005: [PASS][1] -> [DMESG-FAIL][2] +1 other test dmesg-fail
[1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_19242/fi-glk-j4005/igt@i915_selftest@live.html
[2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_172573v5/fi-glk-j4005/igt@i915_selftest@live.html
- bat-apl-1: [PASS][3] -> [DMESG-FAIL][4] +1 other test dmesg-fail
[3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_19242/bat-apl-1/igt@i915_selftest@live.html
[4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_172573v5/bat-apl-1/igt@i915_selftest@live.html
* igt@i915_selftest@live@reset:
- fi-bsw-nick: [PASS][5] -> [DMESG-FAIL][6] +1 other test dmesg-fail
[5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_19242/fi-bsw-nick/igt@i915_selftest@live@reset.html
[6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_172573v5/fi-bsw-nick/igt@i915_selftest@live@reset.html
Build changes
-------------
* Linux: CI_DRM_19242 -> Patchwork_172573v5
CI-20190529: 20190529
CI_DRM_19242: dde43fa4801498eefd0280da6c729ff5a178f866 @ git://anongit.freedesktop.org/gfx-ci/linux
IGT_9118: 26513be3e0f711ed835ec50d5cdcb723ef224105 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
Patchwork_172573v5: dde43fa4801498eefd0280da6c729ff5a178f866 @ git://anongit.freedesktop.org/gfx-ci/linux
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_172573v5/index.html
[-- Attachment #2: Type: text/html, Size: 3189 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest
2026-09-30 11:35 [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Sebastian Brzezinka
2026-09-30 11:46 ` sashiko-bot
2026-09-30 13:22 ` ✗ i915.CI.BAT: failure for drm/i915/selftests: Fix unlocked mm.stolen in reset selftest (rev5) Patchwork
@ 2026-10-01 7:14 ` Krzysztof Karas
2 siblings, 0 replies; 4+ messages in thread
From: Krzysztof Karas @ 2026-10-01 7:14 UTC (permalink / raw)
To: Sebastian Brzezinka
Cc: intel-gfx, andi.shyti, krzysztof.niemiec, chris.p.wilson
Hi Sebastian,
On 2026-09-30 at 13:35:13 +0200, Sebastian Brzezinka wrote:
> _igt_reset_stolen() use via __drm_mm_interval_first(), but
> does so without holding i915->mm.stolen_lock. Every writer of this
> (i915_gem_stolen.c: drm_mm_insert_node_in_range(), drm_mm_reserve_node(),
> drm_mm_remove_node()) takes stolen_lock, so the selftest's unlocked
> reader can race.
>
> This was observed as a NULL pointer dereference in
> __drm_mm_interval_first() during igt_reset_device_stolen():
>
> BUG: kernel NULL pointer dereference, address: 0000000000000010
> ...
> RIP: 0010:__drm_mm_interval_first+0x2c/0x90
> ...
> Call Trace:
> __igt_reset_stolen+0x565/0x6a0 [i915]
> igt_reset_device_stolen+0x1a/0x30 [i915]
> __i915_subtests+0xb8/0x250 [i915]
> ...
>
> Also cap num_pages to i915->dsm.usable_size, which already excludes the
> hardware reserved region from drm_mm.stolen's range, so poison/verify
> writes never touch reserved stolen pages.
>
> Fixes: 3da3c5c1c982 ("drm/i915: Exclude low pages (128KiB) of stolen from use")
> Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16841
> Signed-off-by: Sebastian Brzezinka <sebastian.brzezinka@intel.com>
> ---
> v1 -> v2:
> - Fix always false !__drm_mm_interval_first() check (Andi)
> - Extend stolen_lock over the poison/verify writes, not just
> the lookup (Andi)
> - Move the lookup into stolen_page_unused() helper
>
> v2 -> v3:
> - Cap num_pages to i915->dsm.usable_size to avoid poisoning
> hardware reserved stolen pages (Shashiko)
> ---
> drivers/gpu/drm/i915/gt/selftest_reset.c | 26 ++++++++++++++++--------
> 1 file changed, 18 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c
> index 2cfc23c58e90..811ddf991cb2 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_reset.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c
> @@ -14,6 +14,16 @@
> #include "selftests/igt_atomic.h"
> #include "selftests/igt_spinner.h"
>
> +static bool stolen_page_unused(struct intel_gt *gt, resource_size_t page)
> +{
> + lockdep_assert_held(>->i915->mm.stolen_lock);
> +
> + return __drm_mm_interval_first(>->i915->mm.stolen,
> + page << PAGE_SHIFT,
> + ((page + 1) << PAGE_SHIFT) - 1) ==
> + >->i915->mm.stolen.head_node;
> +}
> +
> static int
> __igt_reset_stolen(struct intel_gt *gt,
> intel_engine_mask_t mask,
> @@ -34,7 +44,8 @@ __igt_reset_stolen(struct intel_gt *gt,
> if (!drm_mm_node_allocated(&ggtt->error_capture))
> return 0;
>
> - num_pages = resource_size(dsm) >> PAGE_SHIFT;
> + num_pages = min_t(resource_size_t, resource_size(dsm),
> + gt->i915->dsm.usable_size) >> PAGE_SHIFT;
> if (!num_pages)
> return 0;
>
> @@ -95,10 +106,10 @@ __igt_reset_stolen(struct intel_gt *gt,
> ggtt->error_capture.start,
> PAGE_SIZE);
>
> - if (!__drm_mm_interval_first(>->i915->mm.stolen,
> - page << PAGE_SHIFT,
> - ((page + 1) << PAGE_SHIFT) - 1))
> + mutex_lock(>->i915->mm.stolen_lock);
> + if (stolen_page_unused(gt, page))
> memset_io(s, STACK_MAGIC, PAGE_SIZE);
> + mutex_unlock(>->i915->mm.stolen_lock);
>
> in = (void __force *)s;
> if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
> @@ -143,16 +154,15 @@ __igt_reset_stolen(struct intel_gt *gt,
> in = tmp;
> x = crc32_le(0, in, PAGE_SIZE);
>
> - if (x != crc[page] &&
> - !__drm_mm_interval_first(>->i915->mm.stolen,
> - page << PAGE_SHIFT,
> - ((page + 1) << PAGE_SHIFT) - 1)) {
> + mutex_lock(>->i915->mm.stolen_lock);
> + if (x != crc[page] && stolen_page_unused(gt, page)) {
> pr_debug("unused stolen page %pa modified by GPU reset\n",
> &page);
> if (count++ == 0)
> igt_hexdump(in, PAGE_SIZE);
> max = page;
> }
> + mutex_unlock(>->i915->mm.stolen_lock);
>
> io_mapping_unmap(s);
> }
> --
> 2.55.0
>
Reviewed-by: Krzysztof Karas <krzysztof.karas@intel.com>
--
Best Regards,
Krzysztof
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-01 7:14 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-30 11:35 [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Sebastian Brzezinka
2026-09-30 11:46 ` sashiko-bot
2026-09-30 13:22 ` ✗ i915.CI.BAT: failure for drm/i915/selftests: Fix unlocked mm.stolen in reset selftest (rev5) Patchwork
2026-10-01 7:14 ` [PATCH v3] drm/i915/selftests: Fix unlocked mm.stolen in reset selftest Krzysztof Karas
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.