Skip to content

Commit a9c4cba

Browse files
misalehmehmetb0
authored andcommitted
iommu/io-pgtable-arm: Fix stage-2 map/unmap for concatenated tables
BugLink: https://bugs.launchpad.net/bugs/2095283 commit d71fa84 upstream. ARM_LPAE_LVL_IDX() takes into account concatenated PGDs and can return an index spanning multiple page-table pages given a sufficiently large input address. However, when the resulting index is used to calculate the number of remaining entries in the page, the possibility of concatenation is ignored and we end up computing a negative upper bound: max_entries = ARM_LPAE_PTES_PER_TABLE(data) - map_idx_start; On the map path, this results in a negative 'mapped' value being returned but on the unmap path we can leak child tables if they are skipped in __arm_lpae_free_pgtable(). Introduce an arm_lpae_max_entries() helper to convert a table index into the remaining number of entries within a single page-table page. Cc: <[email protected]> Signed-off-by: Mostafa Saleh <[email protected]> Link: https://lore.kernel.org/r/[email protected] [will: Tweaked comment and commit message] Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Koichiro Den <[email protected]>
1 parent ed83680 commit a9c4cba

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

drivers/iommu/io-pgtable-arm.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ static phys_addr_t iopte_to_paddr(arm_lpae_iopte pte,
183183
return (paddr | (paddr << (48 - 12))) & (ARM_LPAE_PTE_ADDR_MASK << 4);
184184
}
185185

186+
/*
187+
* Convert an index returned by ARM_LPAE_PGD_IDX(), which can point into
188+
* a concatenated PGD, into the maximum number of entries that can be
189+
* mapped in the same table page.
190+
*/
191+
static inline int arm_lpae_max_entries(int i, struct arm_lpae_io_pgtable *data)
192+
{
193+
int ptes_per_table = ARM_LPAE_PTES_PER_TABLE(data);
194+
195+
return ptes_per_table - (i & (ptes_per_table - 1));
196+
}
197+
186198
static bool selftest_running = false;
187199

188200
static dma_addr_t __arm_lpae_dma_addr(void *pages)
@@ -361,7 +373,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
361373

362374
/* If we can install a leaf entry at this level, then do so */
363375
if (size == block_size) {
364-
max_entries = ARM_LPAE_PTES_PER_TABLE(data) - map_idx_start;
376+
max_entries = arm_lpae_max_entries(map_idx_start, data);
365377
num_entries = min_t(int, pgcount, max_entries);
366378
ret = arm_lpae_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep);
367379
if (!ret && mapped)
@@ -578,7 +590,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
578590

579591
if (size == split_sz) {
580592
unmap_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data);
581-
max_entries = ptes_per_table - unmap_idx_start;
593+
max_entries = arm_lpae_max_entries(unmap_idx_start, data);
582594
num_entries = min_t(int, pgcount, max_entries);
583595
}
584596

@@ -636,7 +648,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
636648

637649
/* If the size matches this level, we're in the right place */
638650
if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) {
639-
max_entries = ARM_LPAE_PTES_PER_TABLE(data) - unmap_idx_start;
651+
max_entries = arm_lpae_max_entries(unmap_idx_start, data);
640652
num_entries = min_t(int, pgcount, max_entries);
641653

642654
while (i < num_entries) {

0 commit comments

Comments
 (0)