On riscv32, it is possible for the last page in virtual address space
(0xfffff000) to be allocated. This page overlaps with PTR_ERR, so that
shouldn't happen.
There is already some code to ensure memblock won't allocate the last page.
However, buddy allocator is left unchecked.
Fix this by reserving physical memory that would be mapped at virtual
addresses greater than 0xfffff000.
Reported-by: Björn Töpel <[email protected]>
Closes: https://lore.kernel.org/linux-riscv/[email protected]
Fixes: 76d2a0493a17 ("RISC-V: Init and Halt Code")
Signed-off-by: Nam Cao <[email protected]>
Cc: <[email protected]>
---
arch/riscv/mm/init.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 968761843203..7c985435b3fc 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -235,18 +235,19 @@ static void __init setup_bootmem(void)
kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base;
/*
- * memblock allocator is not aware of the fact that last 4K bytes of
- * the addressable memory can not be mapped because of IS_ERR_VALUE
- * macro. Make sure that last 4k bytes are not usable by memblock
- * if end of dram is equal to maximum addressable memory. For 64-bit
- * kernel, this problem can't happen here as the end of the virtual
- * address space is occupied by the kernel mapping then this check must
- * be done as soon as the kernel mapping base address is determined.
+ * Reserve physical address space that would be mapped to virtual
+ * addresses greater than (void *)(-PAGE_SIZE) because:
+ * - This memory would overlap with ERR_PTR
+ * - This memory belongs to high memory, which is not supported
+ *
+ * This is not applicable to 64-bit kernel, because virtual addresses
+ * after (void *)(-PAGE_SIZE) are not linearly mapped: they are
+ * occupied by kernel mapping. Also it is unrealistic for high memory
+ * to exist on 64-bit platforms.
*/
if (!IS_ENABLED(CONFIG_64BIT)) {
- max_mapped_addr = __pa(~(ulong)0);
- if (max_mapped_addr == (phys_ram_end - 1))
- memblock_set_current_limit(max_mapped_addr - 4096);
+ max_mapped_addr = __va_to_pa_nodebug(-PAGE_SIZE);
+ memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr);
}
min_low_pfn = PFN_UP(phys_ram_base);
--
2.39.2
Nam Cao <[email protected]> writes:
> On riscv32, it is possible for the last page in virtual address space
> (0xfffff000) to be allocated. This page overlaps with PTR_ERR, so that
> shouldn't happen.
>
> There is already some code to ensure memblock won't allocate the last page.
> However, buddy allocator is left unchecked.
>
> Fix this by reserving physical memory that would be mapped at virtual
> addresses greater than 0xfffff000.
>
> Reported-by: Björn Töpel <[email protected]>
> Closes: https://lore.kernel.org/linux-riscv/[email protected]
> Fixes: 76d2a0493a17 ("RISC-V: Init and Halt Code")
> Signed-off-by: Nam Cao <[email protected]>
> Cc: <[email protected]>
Thanks for picking it up again, Nam.
This passes my test:
Tested-by: Björn Töpel <[email protected]>
> ---
> arch/riscv/mm/init.c | 21 +++++++++++----------
> 1 file changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 968761843203..7c985435b3fc 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -235,18 +235,19 @@ static void __init setup_bootmem(void)
> kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base;
>
> /*
> - * memblock allocator is not aware of the fact that last 4K bytes of
> - * the addressable memory can not be mapped because of IS_ERR_VALUE
> - * macro. Make sure that last 4k bytes are not usable by memblock
> - * if end of dram is equal to maximum addressable memory. For 64-bit
> - * kernel, this problem can't happen here as the end of the virtual
> - * address space is occupied by the kernel mapping then this check must
> - * be done as soon as the kernel mapping base address is determined.
> + * Reserve physical address space that would be mapped to virtual
> + * addresses greater than (void *)(-PAGE_SIZE) because:
> + * - This memory would overlap with ERR_PTR
> + * - This memory belongs to high memory, which is not supported
> + *
> + * This is not applicable to 64-bit kernel, because virtual addresses
> + * after (void *)(-PAGE_SIZE) are not linearly mapped: they are
> + * occupied by kernel mapping. Also it is unrealistic for high memory
> + * to exist on 64-bit platforms.
> */
> if (!IS_ENABLED(CONFIG_64BIT)) {
> - max_mapped_addr = __pa(~(ulong)0);
> - if (max_mapped_addr == (phys_ram_end - 1))
> - memblock_set_current_limit(max_mapped_addr - 4096);
> + max_mapped_addr = __va_to_pa_nodebug(-PAGE_SIZE);
> + memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr);
Nit (and only if you respin for some reason): Move max_mapped_addr into
the if-clause, or simply get rid of it (all on one line).
Regardless:
Reviewed-by: Björn Töpel <[email protected]>
Björn
On Thu, Apr 25, 2024 at 01:52:01PM +0200, Nam Cao wrote:
> On riscv32, it is possible for the last page in virtual address space
> (0xfffff000) to be allocated. This page overlaps with PTR_ERR, so that
> shouldn't happen.
>
> There is already some code to ensure memblock won't allocate the last page.
> However, buddy allocator is left unchecked.
>
> Fix this by reserving physical memory that would be mapped at virtual
> addresses greater than 0xfffff000.
>
> Reported-by: Bj?rn T?pel <[email protected]>
> Closes: https://lore.kernel.org/linux-riscv/[email protected]
> Fixes: 76d2a0493a17 ("RISC-V: Init and Halt Code")
> Signed-off-by: Nam Cao <[email protected]>
> Cc: <[email protected]>
Reviewed-by: Mike Rapoport (IBM) <[email protected]>
> ---
> arch/riscv/mm/init.c | 21 +++++++++++----------
> 1 file changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 968761843203..7c985435b3fc 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -235,18 +235,19 @@ static void __init setup_bootmem(void)
> kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base;
>
> /*
> - * memblock allocator is not aware of the fact that last 4K bytes of
> - * the addressable memory can not be mapped because of IS_ERR_VALUE
> - * macro. Make sure that last 4k bytes are not usable by memblock
> - * if end of dram is equal to maximum addressable memory. For 64-bit
> - * kernel, this problem can't happen here as the end of the virtual
> - * address space is occupied by the kernel mapping then this check must
> - * be done as soon as the kernel mapping base address is determined.
> + * Reserve physical address space that would be mapped to virtual
> + * addresses greater than (void *)(-PAGE_SIZE) because:
> + * - This memory would overlap with ERR_PTR
> + * - This memory belongs to high memory, which is not supported
> + *
> + * This is not applicable to 64-bit kernel, because virtual addresses
> + * after (void *)(-PAGE_SIZE) are not linearly mapped: they are
> + * occupied by kernel mapping. Also it is unrealistic for high memory
> + * to exist on 64-bit platforms.
> */
> if (!IS_ENABLED(CONFIG_64BIT)) {
> - max_mapped_addr = __pa(~(ulong)0);
> - if (max_mapped_addr == (phys_ram_end - 1))
> - memblock_set_current_limit(max_mapped_addr - 4096);
> + max_mapped_addr = __va_to_pa_nodebug(-PAGE_SIZE);
> + memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr);
> }
>
> min_low_pfn = PFN_UP(phys_ram_base);
> --
> 2.39.2
>
--
Sincerely yours,
Mike.
Hello:
This patch was applied to riscv/linux.git (fixes)
by Palmer Dabbelt <[email protected]>:
On Thu, 25 Apr 2024 13:52:01 +0200 you wrote:
> On riscv32, it is possible for the last page in virtual address space
> (0xfffff000) to be allocated. This page overlaps with PTR_ERR, so that
> shouldn't happen.
>
> There is already some code to ensure memblock won't allocate the last page.
> However, buddy allocator is left unchecked.
>
> [...]
Here is the summary with links:
- riscv: fix overlap of allocated page and PTR_ERR
https://git.kernel.org/riscv/c/a5e8a5b08a48
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html