Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 17 Oct 2023 15:55:31 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 6223d0b67af9 - main - linuxkpi: Handle direct-mapped addresses in linux_free_kmem()
Message-ID:  <202310171555.39HFtVnn029019@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=6223d0b67af923f53d962a9bf594dc37004dffe8

commit 6223d0b67af923f53d962a9bf594dc37004dffe8
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-10-17 14:26:18 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-10-17 15:19:06 +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.
    
    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
---
 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?202310171555.39HFtVnn029019>