On Thu, May 11, 2023 at 07:51:58AM +0900, Greg Kroah-Hartman wrote: > On Wed, May 10, 2023 at 04:55:23PM +0800, Ruihan Li wrote: > > Recently, syzbot reported [1] ("kernel BUG in page_table_check_clear"). > > The root cause is that usbdev_mmap calls remap_pfn_range on kmalloc'ed > > memory, which leads to type confusion between struct page and slab in > > page_table_check. This series of patches fixes the usb side by avoiding > > mapping slab pages into userspace, and fixes the mm side by enforcing > > that all user-accessible pages are not slab pages. A more detailed > > analysis and some discussion of how to fix the problem can also be found > > in [1]. > > > > [1] https://lore.kernel.org/lkml/20230507135844.1231056-1-lrh2000@xxxxxxxxxx/T/ > > Can you see if you can implement Christoph's proposed change instead: > https://lore.kernel.org/r/ZFuZVDcU81WmqEvJ@xxxxxxxxxxxxx > > As it might not actually be as bad as you think to require this type of > churn. > > thanks, > > greg k-h Sorry, but no. Christoph's patch perfectly fixes _one_ problem: kmalloc'ed memory cannot be mapped to user space. However, as I detailed in the commit message, this series of patches fixes _three_ problems. I have to say that the original code is quite buggy. In the gen_pool_dma_alloc path, there is no guarantee of page alignment. void *hcd_buffer_alloc(...) { // ... if (hcd->localmem_pool) return gen_pool_dma_alloc(hcd->localmem_pool, size, dma); // ... } When localmem_pool gets initialized, the alignment bits are set to 4 (instead of PAGE_SHIFT). int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, dma_addr_t dma, size_t size) { // ... hcd->localmem_pool = devm_gen_pool_create(hcd->self.sysdev, 4, dev_to_node(hcd->self.sysdev), dev_name(hcd->self.sysdev)); // ... } It is introduced by commit ff2437befd8f ("usb: host: Fix excessive alignment restriction for local memory allocations") [1]. [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ff2437befd8fe52046e0db949347b5bcfab6b097 If you don't believe me, please see my test results. In the following qemu setup, qemu-system-sh4 -M r2d -kernel arch/sh/boot/zImage \ -usb -device usb-storage,drive=d0 \ -drive file=test.img,if=none,id=d0,format=raw \ -append "console=tty0 console=ttySC1,115200 rootwait root=/dev/sda init=/bin/sh" \ -serial null -serial stdio together with the following patch, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index e501a03d6..d7069c986 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -265,6 +265,10 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) INIT_LIST_HEAD(&usbm->memlist); if (hcd->localmem_pool || !hcd_uses_dma(hcd)) { + printk("usb_alloc_coherent returns %px\n", usbm->mem); + printk("so the mapping starts at %lx\n", + virt_to_phys(usbm->mem) >> PAGE_SHIFT); + if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(usbm->mem) >> PAGE_SHIFT, size, vma->vm_page_prot) < 0) { it quickly leads to the following output when I manage to map a page from /dev/bus/usb/001/002, usb_alloc_coherent returns b07c06c0 so the mapping starts at 307c0 What's more, in this case, remap_pfn_range should _not_ be used, since we are going to map a DMA page. However, as you can see, usbdev_mmap actually goes to the wrong path. If you say I shouldn't fix all these bugs in _this_ patch series, that's fine. However, I do think that these bugs should be fixed, perhaps in another patch series. Thanks, Ruihan Li