diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 89 |
1 files changed, 58 insertions, 31 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index e972732..ee73027 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -53,6 +53,23 @@ #include "gsp_phys_gpu.h" #include "gsp_cuda_bridge.h" +/* + * ISSUE-0002 (r75b): bounds for accesses through the emulated vidmem shadow + * at vgpu->bars[1].vaddr. The shadow is sized by the mdev type + * (nv_vgpu_fb_emul_size: 512M/1G/2G) while vgpu->bars[1].size is the physical + * BAR1 aperture exposed to the guest (256M on TU104). Every bounds check that + * guards a shadow dereference must use the shadow size: a legitimate guest + * vidmem offset above the aperture (the pma scrub memset at 262M in a second/ + * third CUDA session) was rejected as -EINVAL against the aperture bound and + * the client froze in scrubCheckAndWaitForSize. Using the shadow size is also + * the safe direction in the inverse case: an aperture larger than the shadow + * would otherwise let a check pass past the vzalloc'd buffer. + */ +static inline u64 svc_fb_shadow_size(const struct nv_vgpu_device *vgpu) +{ + return nv_vgpu_fb_emul_size(vgpu); +} + #define SEMA_MAP_MAX 65536 #define SEMA_MAP_SIZE_BITS 16 #define SEMA_PAGE_SIZE 4096 @@ -874,7 +891,7 @@ static int svc_read_ap(struct nv_vgpu_device *vgpu, u64 addr, u32 aperture, { if (aperture == SVC_APERTURE_FB) { u8 *base = vgpu->bars[1].vaddr; - size_t size = vgpu->bars[1].size; + size_t size = svc_fb_shadow_size(vgpu); if (!base || addr + len > size) return -EINVAL; @@ -889,7 +906,7 @@ static int svc_write_ap(struct nv_vgpu_device *vgpu, u64 addr, u32 aperture, { if (aperture == SVC_APERTURE_FB) { u8 *base = vgpu->bars[1].vaddr; - size_t size = vgpu->bars[1].size; + size_t size = svc_fb_shadow_size(vgpu); if (!base || addr + len > size) return -EINVAL; @@ -1273,7 +1290,7 @@ static int svc_pde_aperture(u32 ap) static bool svc_ap_ok(struct nv_vgpu_device *vgpu, u64 addr, int ap) { if (ap == SVC_APERTURE_FB) - return vgpu->bars[1].vaddr && addr + 8 <= vgpu->bars[1].size; + return vgpu->bars[1].vaddr && addr + 8 <= svc_fb_shadow_size(vgpu); return addr + 8 <= SEMA_PA_MAX; } @@ -1397,10 +1414,20 @@ static int svc_gmmu_walk(struct nv_vgpu_device *vgpu, u64 pdb, u32 entries, if (big & 1) { bap = svc_pte_aperture((big >> 1) & 0x3); if (bap >= 0) { - *addr = svc_pte_addr(big, bap == SVC_APERTURE_FB) + + u64 a = svc_pte_addr(big, bap == SVC_APERTURE_FB) + (va & ((1ULL << 21) - 1)); - *ap = bap; - return 0; + + /* + * ISSUE-0002 (r75b): validate the 2 MB leaf against + * the aperture bounds like every other leaf path; an + * unchecked out-of-shadow result must fall through to + * the shadow fallback, not reach the copy path. + */ + if (svc_ap_ok(vgpu, a, bap)) { + *addr = a; + *ap = bap; + return 0; + } } } bap = svc_pde_aperture((big >> 1) & 0x3); @@ -1603,7 +1630,7 @@ static void svc_pd_discover(struct nv_vgpu_device *vgpu) * matters is the first one of the page. */ for (pass = 0; pass < 2 && !svc_pd_found; pass++) { int ap = pass == 0 ? SVC_APERTURE_SYS : SVC_APERTURE_FB; - u64 limit = pass == 0 ? SEMA_PA_MAX : vgpu->bars[1].size; + u64 limit = pass == 0 ? SEMA_PA_MAX : svc_fb_shadow_size(vgpu); u8 *fb = (u8 *)vgpu->bars[1].vaddr; u64 gpa; @@ -2319,7 +2346,7 @@ static int svc_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr, int *ap) if (!svc_lookup_trusted(vgpu, va, addr, ap)) return 0; if (va >= SVC_VIDMEM_VA_BASE && - va - SVC_VIDMEM_VA_BASE + 4 <= vgpu->bars[1].size) { + va - SVC_VIDMEM_VA_BASE + 4 <= svc_fb_shadow_size(vgpu)) { *addr = va - SVC_VIDMEM_VA_BASE; *ap = SVC_APERTURE_FB; svc_lat_store(va, *addr, *ap); @@ -3679,7 +3706,7 @@ static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem, if (aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - size_t size = vgpu->bars[1].size; + size_t size = svc_fb_shadow_size(vgpu); if (!base || addr + total > size) return -EINVAL; @@ -4147,7 +4174,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, } else if (src_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && src + sizeof(sb) <= vgpu->bars[1].size) + if (base && src + sizeof(sb) <= svc_fb_shadow_size(vgpu)) memcpy(sb, base + src, sizeof(sb)); } else { svc_read(vgpu, src, sb, sizeof(sb)); @@ -4157,7 +4184,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, } else if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && dst + sizeof(db) <= vgpu->bars[1].size) + if (base && dst + sizeof(db) <= svc_fb_shadow_size(vgpu)) memcpy(db, base + dst, sizeof(db)); } else { svc_read(vgpu, dst, db, sizeof(db)); @@ -4259,7 +4286,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (src_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && src + 8 <= vgpu->bars[1].size) + if (base && src + 8 <= svc_fb_shadow_size(vgpu)) memcpy(sb, base + src, 8); } else { svc_read(vgpu, src, sb, 8); @@ -4267,7 +4294,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && dst + 8 <= vgpu->bars[1].size) + if (base && dst + 8 <= svc_fb_shadow_size(vgpu)) memcpy(db, base + dst, 8); } else { svc_read(vgpu, dst, db, 8); @@ -4319,7 +4346,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (src_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && src + n <= vgpu->bars[1].size) + if (base && src + n <= svc_fb_shadow_size(vgpu)) memcpy(peek, base + src, n); } else { svc_read(vgpu, src, peek, n); @@ -4361,7 +4388,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (aper == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (!base || pa + chunk > vgpu->bars[1].size) + if (!base || pa + chunk > svc_fb_shadow_size(vgpu)) return -EINVAL; memcpy(bounce, base + pa, chunk); } else if (svc_read(vgpu, pa, bounce, chunk)) { @@ -4369,7 +4396,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, } } else if (src_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - size_t size = vgpu->bars[1].size; + size_t size = svc_fb_shadow_size(vgpu); if (!base || src + o + chunk > size) return -EINVAL; @@ -4391,7 +4418,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (aper == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (!base || pa + chunk > vgpu->bars[1].size) + if (!base || pa + chunk > svc_fb_shadow_size(vgpu)) return -EINVAL; memcpy(base + pa, bounce, chunk); } else if (svc_write(vgpu, pa, bounce, chunk)) { @@ -4399,7 +4426,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, } } else if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - size_t size = vgpu->bars[1].size; + size_t size = svc_fb_shadow_size(vgpu); if (!base || dst + o + chunk > size) return -EINVAL; @@ -4425,7 +4452,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, } else if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && dst + sizeof(da) <= vgpu->bars[1].size) + if (base && dst + sizeof(da) <= svc_fb_shadow_size(vgpu)) memcpy(da, base + dst, sizeof(da)); } else { svc_read(vgpu, dst, da, sizeof(da)); @@ -4443,7 +4470,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && dst + 8 <= vgpu->bars[1].size) + if (base && dst + 8 <= svc_fb_shadow_size(vgpu)) memcpy(da, base + dst, 8); } else { svc_read(vgpu, dst, da, 8); @@ -4460,7 +4487,7 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, if (dst_aperture == CE_APERTURE_VID) { u8 *base = vgpu->bars[1].vaddr; - if (base && dst + n <= vgpu->bars[1].size) + if (base && dst + n <= svc_fb_shadow_size(vgpu)) memcpy(da, base + dst, n); } else { svc_read(vgpu, dst, da, n); @@ -4530,7 +4557,7 @@ static int svc_grce_inline_write(struct nv_vgpu_device *vgpu, u64 dst_va, if (ap == SVC_APERTURE_FB) { u8 *base = vgpu->bars[1].vaddr; - if (!base || pa + bytes > vgpu->bars[1].size) + if (!base || pa + bytes > svc_fb_shadow_size(vgpu)) return -EINVAL; memcpy(base + pa, data, bytes); } else { @@ -8791,9 +8818,9 @@ static void svc_gr_content_discover(struct nv_vgpu_device *vgpu) * entry0 must sit at the pinned page's offset 0 for the page-granular * pin to be correct. */ - if (vgpu->bars[1].vaddr && vgpu->bars[1].size) { + if (vgpu->bars[1].vaddr && svc_fb_shadow_size(vgpu)) { const u8 *fb = (const u8 *)vgpu->bars[1].vaddr; - u64 lim = min_t(u64, vgpu->bars[1].size, + u64 lim = min_t(u64, svc_fb_shadow_size(vgpu), SVC_GR_CONTENT_FB_LIMIT); u64 off; @@ -9274,9 +9301,9 @@ static void svc_gr_ring_autopin(struct nv_vgpu_device *vgpu, * entry0-shaped word (1 MB aligned push VA, sane length). The * client's ring allocation offset varies per boot; the scan * names the real location for the fix. */ - if (gsp_sema_dbg && vgpu->bars[1].vaddr && vgpu->bars[1].size && + if (gsp_sema_dbg && vgpu->bars[1].vaddr && svc_fb_shadow_size(vgpu) && !svc_fbs_scan_done) { - u64 lim = min_t(u64, vgpu->bars[1].size, 0x20000000ULL); + u64 lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL); u64 off; int hits = 0; @@ -10501,8 +10528,8 @@ static int svc_fwd_operand_hpa(struct nv_vgpu_device *vgpu, u8 kind, u8 *base = vgpu ? vgpu->bars[1].vaddr : NULL; struct page *pg; - if (!base || page > vgpu->bars[1].size || - (u64)page_off + bytes > vgpu->bars[1].size - page) + if (!base || page > svc_fb_shadow_size(vgpu) || + (u64)page_off + bytes > svc_fb_shadow_size(vgpu) - page) return -ERANGE; pg = vmalloc_to_page(base + page); if (!pg) @@ -12858,7 +12885,7 @@ static void svc_userd_sweep(struct nv_vgpu_device *vgpu, struct svc_channel *ch, pr_info("sema-userd-sweep: h=0x%x e0=0x%x e1=0x%x\n", ch->h_object, e0, e1); } - for (off = 0x80000; off + 8 <= vgpu->bars[1].size && off < 0x200000; + for (off = 0x80000; off + 8 <= svc_fb_shadow_size(vgpu) && off < 0x200000; off += 0x1000) { u32 w0, w1; @@ -14927,7 +14954,7 @@ int gsp_sema_service_dump_vidmem(u64 addr, u64 len) return -ENODEV; base = vgpu->bars[1].vaddr; - if (!base || addr + len > vgpu->bars[1].size) + if (!base || addr + len > svc_fb_shadow_size(vgpu)) return -EINVAL; pr_info("sema-vidmem: dump addr=0x%llx len=%llu\n", @@ -14961,7 +14988,7 @@ int gsp_sema_service_find_vidmem(u64 pattern, u64 max_hits) return -ENODEV; base = vgpu->bars[1].vaddr; - size = vgpu->bars[1].size; + size = svc_fb_shadow_size(vgpu); if (!base) return -EINVAL; if (!max_hits) |
