Patch "iommu/amd: Fix corruption when mapping large pages from 0" has been added to the 6.12-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    iommu/amd: Fix corruption when mapping large pages from 0

to the 6.12-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     iommu-amd-fix-corruption-when-mapping-large-pages-fr.patch
and it can be found in the queue-6.12 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 71e3335f38deaecf15f324ecc0ddf0219b3c7adc
Author: Jason Gunthorpe <jgg@xxxxxxxx>
Date:   Fri Oct 18 14:12:19 2024 -0300

    iommu/amd: Fix corruption when mapping large pages from 0
    
    [ Upstream commit e3a682eaf2af51a83f5313145ef592ce50fa787f ]
    
    If a page is mapped starting at 0 that is equal to or larger than can fit
    in the current mode (number of table levels) it results in corrupting the
    mapping as the following logic assumes the mode is correct for the page
    size being requested.
    
    There are two issues here, the check if the address fits within the table
    uses the start address, it should use the last address to ensure that last
    byte of the mapping fits within the current table mode.
    
    The second is if the mapping is exactly the size of the full page table it
    has to add another level to instead hold a single IOPTE for the large
    size.
    
    Since both corner cases require a 0 IOVA to be hit and doesn't start until
    a page size of 2^48 it is unlikely to ever hit in a real system.
    
    Reported-by: Alejandro Jimenez <alejandro.j.jimenez@xxxxxxxxxx>
    Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/0-v1-27ab08d646a1+29-amd_0map_jgg@xxxxxxxxxx
    Signed-off-by: Joerg Roedel <jroedel@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
index 804b788f3f167..f3399087859fd 100644
--- a/drivers/iommu/amd/io_pgtable.c
+++ b/drivers/iommu/amd/io_pgtable.c
@@ -118,6 +118,7 @@ static void free_sub_pt(u64 *root, int mode, struct list_head *freelist)
  */
 static bool increase_address_space(struct amd_io_pgtable *pgtable,
 				   unsigned long address,
+				   unsigned int page_size_level,
 				   gfp_t gfp)
 {
 	struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
@@ -133,7 +134,8 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable,
 
 	spin_lock_irqsave(&domain->lock, flags);
 
-	if (address <= PM_LEVEL_SIZE(pgtable->mode))
+	if (address <= PM_LEVEL_SIZE(pgtable->mode) &&
+	    pgtable->mode - 1 >= page_size_level)
 		goto out;
 
 	ret = false;
@@ -163,18 +165,21 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable,
 		      gfp_t gfp,
 		      bool *updated)
 {
+	unsigned long last_addr = address + (page_size - 1);
 	struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg;
 	int level, end_lvl;
 	u64 *pte, *page;
 
 	BUG_ON(!is_power_of_2(page_size));
 
-	while (address > PM_LEVEL_SIZE(pgtable->mode)) {
+	while (last_addr > PM_LEVEL_SIZE(pgtable->mode) ||
+	       pgtable->mode - 1 < PAGE_SIZE_LEVEL(page_size)) {
 		/*
 		 * Return an error if there is no memory to update the
 		 * page-table.
 		 */
-		if (!increase_address_space(pgtable, address, gfp))
+		if (!increase_address_space(pgtable, last_addr,
+					    PAGE_SIZE_LEVEL(page_size), gfp))
 			return NULL;
 	}
 




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux