From 5ea953292441e31e37ae074e48d8b3b5ce1d9440 Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Tue, 9 Apr 2024 17:19:01 -0400 Subject: Correctly check return code from vram2PRAMIN() Blindly using an invalid return address was resulting in undefined behavior due to traversal of non-page-table addresses as though they were part of the page table. --- mmu.c | 17 ++++++++++++----- nvdebug.h | 1 - 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mmu.c b/mmu.c index 30e9362..e420864 100644 --- a/mmu.c +++ b/mmu.c @@ -15,11 +15,12 @@ /* Convert a physical VRAM address to an offset in the PRAMIN window @param addr VRAM address to convert - @return 0 on error, PRAMIN offset on success + @return -errno on error, PRAMIN offset on success Note: Use off2PRAMIN() instead if you want a dereferenceable address + Note: PRAMIN window is only 1MB, so returning an int is safe */ -uint32_t vram2PRAMIN(struct nvdebug_state *g, uint64_t addr) { +static int vram2PRAMIN(struct nvdebug_state *g, uint64_t addr) { uint64_t pramin_base_va; bar0_window_t window; window.raw = nvdebug_readl(g, NV_PBUS_BAR0_WINDOW); @@ -27,20 +28,26 @@ uint32_t vram2PRAMIN(struct nvdebug_state *g, uint64_t addr) { if (addr & ~0x0001ffffffffffff) { printk(KERN_ERR "[nvdebug] Invalid address %llx passed to %s!\n", addr, __func__); - return 0; + return -EINVAL; } // For unclear (debugging?) reasons, PRAMIN can point to SYSMEM if (window.target != TARGET_VID_MEM) - return 0; + return -EFAULT; pramin_base_va = ((uint64_t)window.base) << 16; // Protect against out-of-bounds accesses if (addr < pramin_base_va || addr > pramin_base_va + NV_PRAMIN_LEN) - return 0; + return -ERANGE; return addr - pramin_base_va; } // Convert a GPU physical address to CPU virtual address via the PRAMIN window +// @return A dereferencable address, or 0 (an invalid physical address) on err void __iomem *phy2PRAMIN(struct nvdebug_state* g, uint64_t phy) { + int off = vram2PRAMIN(g, phy); + if (off == -ERANGE) + printk(KERN_ERR "[nvdebug] Page table walk off end of PRAMIN!\n"); + if (off < 0) + return 0; return g->regs + NV_PRAMIN + vram2PRAMIN(g, phy); } diff --git a/nvdebug.h b/nvdebug.h index 67f2111..567806d 100644 --- a/nvdebug.h +++ b/nvdebug.h @@ -1149,7 +1149,6 @@ int preempt_tsg(struct nvdebug_state *g, uint32_t tsg_id); int preempt_runlist(struct nvdebug_state *g, uint32_t rl_id); // Defined in mmu.c -uint32_t vram2PRAMIN(struct nvdebug_state *g, uint64_t addr); void __iomem *phy2PRAMIN(struct nvdebug_state* g, uint64_t phy); uint64_t search_page_directory( struct nvdebug_state *g, -- cgit v1.2.2