diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-28 16:07:49 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-28 16:07:49 -0400 |
| commit | abde6a6205a7cb2019f0dd1b3bbb2fdb94940a4f (patch) | |
| tree | 79a5f58880a1f99f7fc7acf4c2905f3653aeb30b /kernel/gsp_sema_service.c | |
| parent | 751baee89947a85461b29c019b4744d7610b42d6 (diff) | |
| download | open-iov-abde6a6205a7cb2019f0dd1b3bbb2fdb94940a4f.tar.gz open-iov-abde6a6205a7cb2019f0dd1b3bbb2fdb94940a4f.zip | |
sema: refuse work from buffers that do not start like a push
The discovered VA->PA map is content-scanned and can hand a ring entry's
push VA a false translation; observed: GSP firmware pages read as a
12700-byte method stream whose fills would have been executed into
vidmem. Work now requires the buffer to start with a plausible first
method (INC_METHOD, address 0, sane count that fits the length); releases
still apply from such buffers so a shifted stream is not lost. New
'denied' counter in the sweep stats.
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 5505c1e..ba3690d 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -314,6 +314,7 @@ struct sema_svc { u64 ring_ops; /* op runs from ring-decoded pushes */ u64 lda_log; /* LAUNCH_DMA inventory budget */ u64 entry_log; /* per-push summary budget */ + u64 ops_denied; /* work refused: implausible stream */ u64 releases_seen; u64 releases_applied; u64 releases_missed; /* no VA->PA entry */ @@ -1460,10 +1461,10 @@ static void svc_rebuild(struct nv_vgpu_device *vgpu) svc.releases_stale, svc.releases_jumped, svc.walks_ok, svc.walks_ok + svc.walks_miss, svc.lat_hits, svc_scan_cursor); - pr_info("sema-svc: pages=%llu pushes=%llu pending=%llu nomap=%llu memset=%llu/%llu/%llu ringops=%llu\n", + pr_info("sema-svc: pages=%llu pushes=%llu pending=%llu nomap=%llu memset=%llu/%llu/%llu ringops=%llu denied=%llu\n", svc.pages_decoded, svc.pushes_seen, svc.pushes_pending, svc.pushes_nomap, svc.memsets_done, svc.memsets_nomap, - svc.memsets_fail, svc.ring_ops); + svc.memsets_fail, svc.ring_ops, svc.ops_denied); pr_info("sema-svc: gpfifo done=%llu nomap=%llu vidmem_writes=%llu ring_auto=%u pb=%u/%u\n", svc.gpfifo_entries_done, svc.gpfifo_nomap, svc.vidmem_writes, svc_ring_n, svc_pb_n, svc_pb_passes); @@ -1732,6 +1733,29 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, u32 ops_runs = 0; u32 off = 0; + /* + * A false VA->PA pair (the discovered map is content-scanned) can + * point a ring entry's push VA at an unrelated page - observed: + * GSP firmware pages decoded as a 12700-byte "method stream" whose + * fills would have been executed into vidmem. Work may only run + * when the buffer starts like a push (first method: op=INC_METHOD, + * addr 0, sane count). Releases from such a page still apply, so a + * genuinely shifted stream is not lost. + */ + if (allow_ops) { + u32 hdr = 0, op = 0, count = 0; + + if (len >= 8) + memcpy(&hdr, buf, 4); + op = (hdr >> 29) & 0x7; + count = (hdr >> 16) & 0xfff; + if (op != 1 || !count || count > 64 || + 4 + count * 4 > len || ((hdr & 0x1fff) << 2) != 0) { + svc.ops_denied++; + allow_ops = false; + } + } + memset(&st, 0, sizeof(st)); svc.pages_decoded++; |
