Re: git: e0e8d0c8d694 - main - iommu_gas: consolidate find_space helpers

From: Andrew Turner <andrew_at_fubar.geek.nz>
Date: Tue, 20 Dec 2022 19:32:04 UTC
> On 10 Jul 2022, at 20:39, Doug Moore <dougm@freebsd.org> wrote:
> 
> The branch main has been updated by dougm:
> 
> URL: https://cgit.FreeBSD.org/src/commit/?id=e0e8d0c8d69459c7128e6fd4fb537892445ce710
> 
> commit e0e8d0c8d69459c7128e6fd4fb537892445ce710
> Author:     Doug Moore <dougm@FreeBSD.org>
> AuthorDate: 2022-07-10 19:24:23 +0000
> Commit:     Doug Moore <dougm@FreeBSD.org>
> CommitDate: 2022-07-10 19:24:23 +0000
> 
>    iommu_gas: consolidate find_space helpers
> 
>    Merge lowermatch and uppermatch into find_space.  Eliminate uppermatch
>    recursion.  Merge match_insert into match_one and eliminate some
>    redundant calculation.  Move some initialization out of find_space and
>    into map (and out from under a lock).
> 

This commit introduced an integer overflow that breaks the iommu on arm64.

In iommu_gas_find_space it adds "addr = a->common->lowaddr + 1;”, however when lowaddr is (bus_addr_t)-1 it will overflow making addr 0. We then use this to set the bounds in iommu_gas_match_one, however this will fail as the bounds are 0, 0.

When this first loops fails it then searches for address space above highaddr, however as this is above the maximum address this loop is never run.

As far as I can tell it works on amd64 because of another integer overflow in the loop to find memory above highaddr where, due to it also overflowing, it incorrectly uses 0 and domain->end as the bounds. It can get into this case as curr->last == (bus_addr_t)-1 so the RB_PARENT loop will exit with a non-NULL curr pointer.

D37756 works around this issue by making arm64 behave in the same way as amd64, however I don’t think we should be entering the second loop with a highaddr of (bus_addr_t)-1 as it may lead to an invalid address being allocated, e.g. If the first loop failed because it is out of usable address space.

Andrew