DF-2207 / fix.diff
diff --git a/sys/dev/drm/linux_iomapping.c b/sys/dev/drm/linux_iomapping.c index 0000000..1111111 100644 --- a/sys/dev/drm/linux_iomapping.c +++ b/sys/dev/drm/linux_iomapping.c @@ -64,6 +64,7 @@ int found = 0; int indx; vm_paddr_t paddr_end; + size_t byte_size; SLIST_FOREACH_MUTABLE(imp, &iomap_list, im_iomaps, tmp_imp) { if (imp->pmap_addr == ptr) { @@ -77,7 +78,16 @@ return; } - paddr_end = imp->paddr + (imp->npages * PAGE_SIZE) - 1; + /* + * DF-2207: Compute byte_size once as size_t so the npages * PAGE_SIZE + * multiplication cannot overflow signed int. struct iomap.npages is + * int (asm/io.h) and PAGE_SIZE is (1<<PAGE_SHIFT) which also has type + * int (param.h), so the bare product is a signed multiplication that + * overflows (UB) for mappings >= ~2 GiB and sign-extends into the + * unsigned long arguments of pmap_unmapdev()/pmap_change_attr(). + */ + byte_size = (size_t)imp->npages * PAGE_SIZE; + paddr_end = imp->paddr + byte_size - 1; /* Is this address space range backed by regular memory ? */ for (indx = 0; phys_avail[indx].phys_end != 0; ++indx) { vm_paddr_t range_start = phys_avail[indx].phys_beg; @@ -93,7 +103,7 @@ } - pmap_unmapdev((vm_offset_t)imp->pmap_addr, imp->npages * PAGE_SIZE); + pmap_unmapdev((vm_offset_t)imp->pmap_addr, byte_size); lockmgr(&iomap_lock, LK_EXCLUSIVE); SLIST_REMOVE(&iomap_list, imp, iomap, im_iomaps); |