summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c85
1 files changed, 76 insertions, 9 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 9730c58..efb4fc1 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -15838,12 +15838,78 @@ struct svc_fb_push_hit {
u64 off;
};
-static bool svc_fb_push_rescue(struct nv_vgpu_device *vgpu, u64 va, u32 len,
- u8 *out, u64 *off_out)
+/*
+ * CONT.445 follow-up: content-identity gate for the FB push rescue. The raw
+ * method-stream parse alone cannot admit a rescue window: op 7 (END_PB_
+ * SEGMENT) and op 0 (SET/STORE/USE_SUB_DEV_MASK) are 4-byte header-only
+ * forms, so a fill window (0xff000000 / 0x00000000 / one repeated dword)
+ * parses cleanly - the V36 rescue false-positived on exactly such an X
+ * screen fill. A real setup/draw push carries multi-word INC runs and a
+ * variety of method headers; require both, so a fill can never win.
+ */
+static bool svc_fb_push_window_ok(const u8 *buf, u32 len)
+{
+ u32 off = 0, inc = 0;
+ u32 seen[64];
+ u32 nseen = 0;
+
+ if (!svc_method_stream_plausible(buf, len))
+ return false;
+ while (off + 4 <= len) {
+ u32 hdr, op, cnt;
+
+ memcpy(&hdr, buf + off, 4);
+ op = (hdr >> 29) & 7u;
+ cnt = (hdr >> 16) & 0xfffu;
+ if (op == 1u || op == 3u || op == 5u) {
+ if (!cnt || cnt > 0xfff ||
+ off + 4 + cnt * 4u > len)
+ return false;
+ if (cnt >= 2)
+ inc++;
+ off += 4 + cnt * 4u;
+ } else if (op == 0u || op == 2u || op == 4u || op == 7u) {
+ if (nseen < ARRAY_SIZE(seen)) {
+ u32 i;
+ bool dup = false;
+
+ for (i = 0; i < nseen; i++)
+ if (seen[i] == hdr) {
+ dup = true;
+ break;
+ }
+ if (!dup)
+ seen[nseen++] = hdr;
+ }
+ off += 4;
+ } else {
+ return false;
+ }
+ }
+ /*
+ * Measured real pushes: the 59556-byte setup stream and the 6400-byte
+ * draw streams carry many distinct method headers and several
+ * multi-word INC runs. 8 distinct headers + 2 INC runs is well below
+ * any observed real stream and far above any fill window (1 header,
+ * 0 INC runs).
+ */
+ return inc >= 2 && nseen >= 8;
+}
+
+static bool svc_fb_push_rescue(struct nv_vgpu_device *vgpu, u32 h_object,
+ u64 va, u32 len, u8 *out, u64 *off_out)
{
static struct svc_fb_push_hit hits[8];
u8 *base = vgpu->bars[1].vaddr;
u64 lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x4000000ULL), off;
+ /*
+ * The client writes the pushbuffer at its VA's page offset inside the
+ * BAR1 window, so a push whose VA is 0x...004 starts 4 bytes into a
+ * shadow page. Scan at that same in-page offset (the old page-aligned
+ * scan could never match such a push - e.g. the 59556-byte setup
+ * push at va 0x4041004).
+ */
+ u32 poff = (u32)(va & (SEMA_PAGE_SIZE - 1));
static u32 log;
int i;
@@ -15855,19 +15921,19 @@ static bool svc_fb_push_rescue(struct nv_vgpu_device *vgpu, u64 va, u32 len,
for (i = 0; i < ARRAY_SIZE(hits); i++) {
if (hits[i].n && hits[i].len == len &&
hits[i].off + len <= lim &&
- svc_method_stream_plausible(base + hits[i].off, len)) {
+ svc_fb_push_window_ok(base + hits[i].off, len)) {
memcpy(out, base + hits[i].off, len);
*off_out = hits[i].off;
return true;
}
}
/* Cheap first: the first 64 bytes must parse as a stream prefix. */
- for (off = 0; off + len <= lim; off += SEMA_PAGE_SIZE) {
+ for (off = poff; off + len <= lim; off += SEMA_PAGE_SIZE) {
u32 pre = min_t(u32, len, 64);
if (!svc_method_stream_plausible(base + off, pre))
continue;
- if (!svc_method_stream_plausible(base + off, len))
+ if (!svc_fb_push_window_ok(base + off, len))
continue;
memcpy(out, base + off, len);
*off_out = off;
@@ -15881,15 +15947,15 @@ static bool svc_fb_push_rescue(struct nv_vgpu_device *vgpu, u64 va, u32 len,
}
if (log < 16) {
log++;
- pr_info("sema-chan: FB-PUSH rescue h=0x%x va=0x%llx len=%u -> fb 0x%llx (plausible window; pinned for later reads)\n",
- va, len, off);
+ pr_info("sema-chan: FB-PUSH rescue h=0x%x va=0x%llx len=%u -> fb 0x%llx (content-gated window; pinned for later reads)\n",
+ h_object, va, len, off);
}
return true;
}
if (log < 16) {
log++;
- pr_info("sema-chan: FB-PUSH rescue h=0x%x va=0x%llx len=%u: no plausible window in 0x%llx shadow\n",
- va, len, lim);
+ pr_info("sema-chan: FB-PUSH rescue h=0x%x va=0x%llx len=%u: no content-gated window in 0x%llx shadow\n",
+ h_object, va, len, lim);
}
return false;
}
@@ -46377,6 +46443,7 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
u64 fbo = 0;
if (svc_fb_push_rescue(vgpu,
+ ch->h_object,
va, len,
pb, &fbo)) {
ok = true;