Date: Wed, 25 Oct 2023 16:56:41 GMT From: Mark Johnston <markj@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 87dbb943df73 - releng/14.0 - linuxkpi: Handle direct-mapped addresses in linux_free_kmem() Message-ID: <202310251656.39PGufSW021916@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch releng/14.0 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=87dbb943df73022dd98487c123aeb125da11c4af commit 87dbb943df73022dd98487c123aeb125da11c4af Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2023-10-17 14:26:18 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2023-10-25 16:53:01 +0000 linuxkpi: Handle direct-mapped addresses in linux_free_kmem() See the analysis in PR 271333. It is possible for driver code to allocate a page, store its address as returned by page_address(), then call free_page() on that address. On most systems that'll result in the LinuxKPI calling kmem_free() with a direct-mapped address, which is not legal. Fix the problem by making linux_free_kmem() check the address to see whether it's direct-mapped or not, and handling it appropriately. Approved by: re (gjb) PR: 271333, 274515 Reviewed by: hselasky, bz Tested by: trasz MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D40028 (cherry picked from commit 6223d0b67af923f53d962a9bf594dc37004dffe8) (cherry picked from commit 4862eb8604d503b52e7c3aa7ff32155b75a1ff93) --- sys/compat/linuxkpi/common/src/linux_page.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c index ce9ad34464bd..21e338acb089 100644 --- a/sys/compat/linuxkpi/common/src/linux_page.c +++ b/sys/compat/linuxkpi/common/src/linux_page.c @@ -145,6 +145,14 @@ linux_alloc_pages(gfp_t flags, unsigned int order) return (page); } +static void +_linux_free_kmem(vm_offset_t addr, unsigned int order) +{ + size_t size = ((size_t)PAGE_SIZE) << order; + + kmem_free((void *)addr, size); +} + void linux_free_pages(struct page *page, unsigned int order) { @@ -163,7 +171,7 @@ linux_free_pages(struct page *page, unsigned int order) vaddr = (vm_offset_t)page_address(page); - linux_free_kmem(vaddr, order); + _linux_free_kmem(vaddr, order); } } @@ -185,9 +193,17 @@ linux_alloc_kmem(gfp_t flags, unsigned int order) void linux_free_kmem(vm_offset_t addr, unsigned int order) { - size_t size = ((size_t)PAGE_SIZE) << order; + KASSERT((addr & PAGE_MASK) == 0, + ("%s: addr %p is not page aligned", __func__, (void *)addr)); - kmem_free((void *)addr, size); + if (addr >= VM_MIN_KERNEL_ADDRESS && addr < VM_MAX_KERNEL_ADDRESS) { + _linux_free_kmem(addr, order); + } else { + vm_page_t page; + + page = PHYS_TO_VM_PAGE(DMAP_TO_PHYS(addr)); + linux_free_pages(page, order); + } } static int
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202310251656.39PGufSW021916>