summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index ec269c5..7d690ab 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -12129,6 +12129,56 @@ static bool svc_gr_page_inline_covers(u64 page)
static u32 svc_gr_data_log; /* m142: bounded per-page attribution log */
+/*
+ * m144 (second-client launch-state divergence): collect device-VA-shaped
+ * candidate pointers from the bytes the ENGINE will actually execute.
+ *
+ * The guest page read through the operand HPA can be STALE across a session
+ * boundary: the guest reuses the previous client's physical page for the new
+ * client's parameter/bank page, and at scan time that page can still hold the
+ * previous client's device VAs (observed r97: the second client's data fill
+ * read the first client's VAs, resolved zero pages, relocated nothing, and
+ * the engine then executed the kernel against the ORIGINAL unrelocated
+ * pointers - the win0 param page kept 0x75552ec00000 instead of 0x110000).
+ * The driver ALSO writes the kernel parameter block inline; those bytes are
+ * captured fresh from the launch pushbuffer at request time and are overlaid
+ * onto the shadow page by the backend. Scan them too (the scan is by value,
+ * so the in-page offset of an inline record does not matter) so pointer
+ * discovery is independent of guest-page reuse timing.
+ */
+static void svc_gr_scan_cand(u64 *wins, u32 *n_cand, const u8 *data, u32 bytes)
+{
+ u32 k;
+
+ for (k = 0; k + 8 <= bytes; k += 8) {
+ u64 v = get_unaligned_le64(data + k);
+ u64 wv;
+ u32 w;
+
+ if (v < 0x10000000ULL || v >= (1ULL << 47) || (v & 3))
+ continue;
+ wv = v & ~(u64)(SEMA_PAGE_SIZE - 1);
+ for (w = 0; w < *n_cand; w++)
+ if (wins[w] == wv)
+ break;
+ if (w == *n_cand && *n_cand < 16u)
+ wins[(*n_cand)++] = wv;
+ }
+}
+
+static void svc_gr_scan_inline(u64 *wins, u32 *n_cand, u64 page_va)
+{
+ u32 j;
+
+ for (j = 0; j < svc_gr_cand.n_inline && j < SVC_GR_INLINE_MAX; j++) {
+ const struct svc_gr_inline *inl = &svc_gr_cand.inline_recs[j];
+
+ if ((inl->dst_va & ~(u64)(SEMA_PAGE_SIZE - 1)) != page_va)
+ continue;
+ svc_gr_scan_cand(wins, n_cand, inl->data, inl->len);
+ }
+}
+
static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
{
u64 wins[16];
@@ -12185,6 +12235,10 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
if (w == n_cand && n_cand < ARRAY_SIZE(wins))
wins[n_cand++] = wv;
}
+ /* m144: also scan the fresh inline-captured parameter block,
+ * so a reused/stale guest page cannot hide the kernel's device
+ * pointers. */
+ svc_gr_scan_inline(wins, &n_cand, pp->va);
}
for (i = 0; i < svc_fwd_req.gr_n_pages; i++) {
const struct svc_gr_page *pp = &svc_fwd_req.gr_pages[i];
@@ -12217,6 +12271,9 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
if (w == n_cand && n_cand < ARRAY_SIZE(wins))
wins[n_cand++] = wv;
}
+ /* m144: bank pages carry their own pointers too; scan the fresh
+ * inline-captured bytes as well (see svc_gr_scan_inline). */
+ svc_gr_scan_inline(wins, &n_cand, pp->va);
}
/* m110: one contiguous run of pages per candidate pointer, relocated
* into the engine-walkable main-PT window (0x110000 onward, fresh