diff options
| -rw-r--r-- | kernel/gsp_sema_service.c | 35 | ||||
| -rwxr-xr-x | tools/guest-diag/sempages.py | 22 |
2 files changed, 47 insertions, 10 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index bf6bb01..40926ee 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -1719,7 +1719,7 @@ static void svc_run_ops(struct nv_vgpu_device *vgpu, struct svc_memset_op *ops, * skipped, so their stale memsets never overwrite newer state. */ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, - u32 len, u64 page_pa) + u32 len, u64 page_pa, bool allow_ops) { struct svc_push_state st; struct svc_memset_op ops[SVC_MAX_MEMSETS]; @@ -1886,7 +1886,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, if (st.rs_payload <= cur) break; svc.pushes_pending++; - svc_run_ops(vgpu, ops, n_ops); + if (allow_ops) + svc_run_ops(vgpu, ops, n_ops); n_ops = 0; if (!svc_sem_write(vgpu, va, st.rs_payload)) @@ -1953,7 +1954,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, u32 dma = v0; u32 transfer = DMA_DATA_TRANSFER_TYPE(dma); - if (transfer != 0 && st.line_length && st.have_out) { + if (allow_ops && transfer != 0 && st.line_length && + st.have_out) { if (DMA_REMAP_ENABLE(dma) && st.have_remap && DMA_DST_MEMORY_LAYOUT_PITCH(dma) && n_ops < SVC_MAX_MEMSETS) { @@ -2014,7 +2016,8 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, if (pending) { svc.pushes_pending++; - svc_run_ops(vgpu, ops, n_ops); + if (allow_ops) + svc_run_ops(vgpu, ops, n_ops); if (DMA_SEM_REDUCTION_EN(dma) && DMA_SEM_REDUCTION(dma) == SEM_REDUCTION_INC) @@ -2137,8 +2140,15 @@ static u32 svc_apply_page_data(struct nv_vgpu_device *vgpu, const u8 *buf, * Decoded execution: walk the page as a method stream and perform the * pushed work (PTE memsets, semaphore releases) for pushes that are * still pending. + * + * This page was reached by sweeping raw guest RAM, so the data is + * arbitrary: only the bounded semaphore-release writes below may be + * attempted. Executing fills/copies decoded from a swept page is what + * made the sweep corrupt live guest kernel memory (65M pages scanned, + * fabricated "pushes" executing memsets); work execution is limited + * to pushes the pump read through a trusted ring translation. */ - svc_decode_stream(vgpu, buf, SEMA_PAGE_SIZE, pa_page); + svc_decode_stream(vgpu, buf, SEMA_PAGE_SIZE, pa_page, false); for (off = 0; off + 16 <= SEMA_PAGE_SIZE; off += 4) { u32 hdr, hi, lo, payload; @@ -3185,8 +3195,18 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) if (pb) { if (!svc_read_va_trusted(vgpu, va, pb, len)) { + /* + * Fills/copies execute only for CE + * channels: the push was written for the + * copy engine, so its method space is + * CE's. Compute pushes (context binds, + * work submissions) carry releases we + * need but their other methods may + * alias CE encodings. + */ svc_decode_stream(vgpu, pb, - len, 0); + len, 0, + ch->engine_type != 0); ch->submissions++; svc.gpfifo_entries_done++; /* Advance expected payload for this channel's tracking semaphore. */ @@ -3205,7 +3225,8 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu) if (!svc_read_va_trusted(vgpu, va, pb, len)) { svc_decode_stream(vgpu, pb, - len, 0); + len, 0, + ch->engine_type != 0); ch->submissions++; svc.gpfifo_entries_done++; if (ch->engine_type && ch->expected_sem_payload) diff --git a/tools/guest-diag/sempages.py b/tools/guest-diag/sempages.py index ad4dae6..f8d15b2 100755 --- a/tools/guest-diag/sempages.py +++ b/tools/guest-diag/sempages.py @@ -29,9 +29,25 @@ else: raise SystemExit(1) fd = os.open('/proc/%d/mem' % pid, os.O_RDONLY) -sems = m.sem_objs(pid, fd, lo, hi) +# Pin what libcuda actually polls: the semaphore objects referenced by the +# client's trackers (and the semaphore memory they point at). Scanning for +# bare sem-object shapes matches far too many pages once the ring/pushbuffer +# windows are in range; trackers are a structural reference, so pinning is +# limited to pages the client really waits on. Fall back to the shape scan +# only when no tracker resolves. +pages = set() +trackers = m.find_trackers(pid, fd, lo, hi, limit=256) +for _p, _sub, _last, _cur, sem, mem in trackers: + if sem: + pages.add(sem & ~0xfff) + if mem: + pages.add(mem & ~0xfff) +if not pages: + sems = m.sem_objs(pid, fd, lo, hi) + pages = {va & ~0xfff for va in sems} os.close(fd) -pages = sorted({va & ~0xfff for va in sems}) -print('sem VAs: %d pages: %d (window 0x%x..0x%x)' % (len(sems), len(pages), lo, hi)) +pages = sorted(pages) +print('trackers: %d pages: %d (window 0x%x..0x%x)' % + (len(trackers), len(pages), lo, hi)) for pg in pages: print('0x%x' % pg) |
