[PATCH] arm64: kaslr: consider parange is bigger than linear_region_size

Keun-O Park posted 1 patch 9 months, 3 weeks ago
arch/arm64/mm/init.c | 5 +++++
1 file changed, 5 insertions(+)
[PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Keun-O Park 9 months, 3 weeks ago
From: Keuno Park <keun-o.park@katim.com>

On systems using 4KB pages and having 39 VA_BITS, linear_region_size
gets 256GiB space. It was observed that some SoCs such as Qualcomm
QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
value to have minus as the variable range is s64, so that all the
calculations for randomizing linear address space are skpped.
As a result of this, the kernel's linear region is not randomized.
For this case, this patch sets the range by calculating memblock
DRAM range to randomize the linear region of kernel.

Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
Signed-off-by: Keuno Park <keun-o.park@katim.com>
---
 arch/arm64/mm/init.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 9c0b8d9558fc..2ee657e2d60f 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -290,6 +290,11 @@ void __init arm64_memblock_init(void)
 		s64 range = linear_region_size -
 			    BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
 
+		if (range < 0) {
+			range = linear_region_size -
+				(memblock_end_of_DRAM() - memblock_start_of_DRAM());
+		}
+
 		/*
 		 * If the size of the linear region exceeds, by a sufficient
 		 * margin, the size of the region that the physical memory can
-- 
2.34.1
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Keun-O Park 9 months, 3 weeks ago
On Mon, Feb 24, 2025 at 10:21 AM Keun-O Park <kpark3469@gmail.com> wrote:
>
> From: Keuno Park <keun-o.park@katim.com>
>
> On systems using 4KB pages and having 39 VA_BITS, linear_region_size
> gets 256GiB space. It was observed that some SoCs such as Qualcomm
> QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
> value to have minus as the variable range is s64, so that all the
> calculations for randomizing linear address space are skpped.
> As a result of this, the kernel's linear region is not randomized.
> For this case, this patch sets the range by calculating memblock
> DRAM range to randomize the linear region of kernel.
>
> Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
> Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
> Signed-off-by: Keuno Park <keun-o.park@katim.com>
> ---
>  arch/arm64/mm/init.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9c0b8d9558fc..2ee657e2d60f 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -290,6 +290,11 @@ void __init arm64_memblock_init(void)
>                 s64 range = linear_region_size -
>                             BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
>
> +               if (range < 0) {
> +                       range = linear_region_size -
> +                               (memblock_end_of_DRAM() - memblock_start_of_DRAM());
> +               }
> +
>                 /*
>                  * If the size of the linear region exceeds, by a sufficient
>                  * margin, the size of the region that the physical memory can
> --
> 2.34.1
>

36bit: linear_region_size=0x800000000 32 GB
39bit: linear_region_size=0x4000000000 256 GB
42bit: linear_region_size=0x20000000000 2048 GB, 2 TB
47bit: linear_region_size=0x400000000000 65536 GB, 64 TB
48bit: linear_region_size=0x800000000000 131072 GB, 128 TB
52bit: linear_region_size=0xf800000000000 4063232 GB, 3968 TB

The problem happens only when linear_region_size is smaller than
BIT(id_aa64mmfr0_parange_to_phys_shift(parange)).
In my case, SoC returns 2 as parange value. (va_bits is 39bit, so the
linear_region_size gets 0x4000000000, 256GB.)
#define ID_AA64MMFR0_PARANGE_40         0x2
BIT(id_aa64mmfr0_parange_to_phys_shift(parange)) == 0x10000000000, 1TB

                s64 range = linear_region_size -
                            BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
As a result, range gets a negative value. 0xffffff4000000000 in here.
So this makes randomization code bypass as range is smaller than
ARM64_MEMSTART_ALIGN.

                if (memstart_offset_seed > 0 && range >=
(s64)ARM64_MEMSTART_ALIGN) {

In most cases, the hotplug memory code will be working the same as before.
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Ard Biesheuvel 9 months, 3 weeks ago
On Tue, 25 Feb 2025 at 05:48, Keun-O Park <kpark3469@gmail.com> wrote:
>
> On Mon, Feb 24, 2025 at 10:21 AM Keun-O Park <kpark3469@gmail.com> wrote:
> >
> > From: Keuno Park <keun-o.park@katim.com>
> >
> > On systems using 4KB pages and having 39 VA_BITS, linear_region_size
> > gets 256GiB space. It was observed that some SoCs such as Qualcomm
> > QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
> > value to have minus as the variable range is s64, so that all the
> > calculations for randomizing linear address space are skpped.
> > As a result of this, the kernel's linear region is not randomized.
> > For this case, this patch sets the range by calculating memblock
> > DRAM range to randomize the linear region of kernel.
> >
> > Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
> > Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
> > Signed-off-by: Keuno Park <keun-o.park@katim.com>
> > ---
> >  arch/arm64/mm/init.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> >
> > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > index 9c0b8d9558fc..2ee657e2d60f 100644
> > --- a/arch/arm64/mm/init.c
> > +++ b/arch/arm64/mm/init.c
> > @@ -290,6 +290,11 @@ void __init arm64_memblock_init(void)
> >                 s64 range = linear_region_size -
> >                             BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
> >
> > +               if (range < 0) {
> > +                       range = linear_region_size -
> > +                               (memblock_end_of_DRAM() - memblock_start_of_DRAM());
> > +               }
> > +
..
>
> In most cases, the hotplug memory code will be working the same as before.

How so? Such memory will usually appear above memblock_end_of_DRAM(),
and due to the randomization, there may not be any space left there.
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Keun-O Park 9 months, 3 weeks ago
How about adding a warning message in case of linear region
randomization failure?
And, there might be two options in my mind by now to consider hotplug memory.
Either giving an option for users to override "parange" as kernel
param or providing the legacy way((memblock_end_of_DRAM() -
memblock_start_of_DRAM()) when CONFIG_MEMORY_HOTPLUG is off.
Users believe KASLR will work fine by enabling CONFIG_RANDOMIZE_BASE.
In case of linear region randomization failure, I think at least users
need to know about this failure.
Can you share your thoughts on this please?

On Tue, Feb 25, 2025 at 12:28 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Tue, 25 Feb 2025 at 05:48, Keun-O Park <kpark3469@gmail.com> wrote:
> >
> > On Mon, Feb 24, 2025 at 10:21 AM Keun-O Park <kpark3469@gmail.com> wrote:
> > >
> > > From: Keuno Park <keun-o.park@katim.com>
> > >
> > > On systems using 4KB pages and having 39 VA_BITS, linear_region_size
> > > gets 256GiB space. It was observed that some SoCs such as Qualcomm
> > > QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
> > > value to have minus as the variable range is s64, so that all the
> > > calculations for randomizing linear address space are skpped.
> > > As a result of this, the kernel's linear region is not randomized.
> > > For this case, this patch sets the range by calculating memblock
> > > DRAM range to randomize the linear region of kernel.
> > >
> > > Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
> > > Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
> > > Signed-off-by: Keuno Park <keun-o.park@katim.com>
> > > ---
> > >  arch/arm64/mm/init.c | 5 +++++
> > >  1 file changed, 5 insertions(+)
> > >
> > > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> > > index 9c0b8d9558fc..2ee657e2d60f 100644
> > > --- a/arch/arm64/mm/init.c
> > > +++ b/arch/arm64/mm/init.c
> > > @@ -290,6 +290,11 @@ void __init arm64_memblock_init(void)
> > >                 s64 range = linear_region_size -
> > >                             BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
> > >
> > > +               if (range < 0) {
> > > +                       range = linear_region_size -
> > > +                               (memblock_end_of_DRAM() - memblock_start_of_DRAM());
> > > +               }
> > > +
> ..
> >
> > In most cases, the hotplug memory code will be working the same as before.
>
> How so? Such memory will usually appear above memblock_end_of_DRAM(),
> and due to the randomization, there may not be any space left there.
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Ard Biesheuvel 9 months, 3 weeks ago
On Fri, 28 Feb 2025 at 06:55, Keun-O Park <kpark3469@gmail.com> wrote:
>
> How about adding a warning message in case of linear region
> randomization failure?
> And, there might be two options in my mind by now to consider hotplug memory.
> Either giving an option for users to override "parange" as kernel
> param or providing the legacy way((memblock_end_of_DRAM() -
> memblock_start_of_DRAM()) when CONFIG_MEMORY_HOTPLUG is off.
> Users believe KASLR will work fine by enabling CONFIG_RANDOMIZE_BASE.
> In case of linear region randomization failure, I think at least users
> need to know about this failure.
> Can you share your thoughts on this please?
>

Randomization of the linear map has always been a best effort thing,
so I don't think this is a big deal.

I wouldn't object to the new behavior being conditional on
CONFIG_MEMORY_HOTPLUG, and fallback to the old behavior otherwise. But
ultimately, it will be up to the maintainers.
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Will Deacon 9 months, 2 weeks ago
On Fri, Feb 28, 2025 at 02:11:41PM +0100, Ard Biesheuvel wrote:
> On Fri, 28 Feb 2025 at 06:55, Keun-O Park <kpark3469@gmail.com> wrote:
> >
> > How about adding a warning message in case of linear region
> > randomization failure?
> > And, there might be two options in my mind by now to consider hotplug memory.
> > Either giving an option for users to override "parange" as kernel
> > param or providing the legacy way((memblock_end_of_DRAM() -
> > memblock_start_of_DRAM()) when CONFIG_MEMORY_HOTPLUG is off.
> > Users believe KASLR will work fine by enabling CONFIG_RANDOMIZE_BASE.
> > In case of linear region randomization failure, I think at least users
> > need to know about this failure.
> > Can you share your thoughts on this please?
> >
> 
> Randomization of the linear map has always been a best effort thing,
> so I don't think this is a big deal.
> 
> I wouldn't object to the new behavior being conditional on
> CONFIG_MEMORY_HOTPLUG, and fallback to the old behavior otherwise. But
> ultimately, it will be up to the maintainers.

Personally, given the confusion that linear map randomization seems to
cause, I'd rather reduce the number of variables on which it depends.

I also wonder whether it's actually useful at all...

Will
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Keun-O Park 9 months, 2 weeks ago
On Sat, Mar 1, 2025 at 8:39 AM Will Deacon <will@kernel.org> wrote:
>
> On Fri, Feb 28, 2025 at 02:11:41PM +0100, Ard Biesheuvel wrote:
> > On Fri, 28 Feb 2025 at 06:55, Keun-O Park <kpark3469@gmail.com> wrote:
> > >
> > > How about adding a warning message in case of linear region
> > > randomization failure?
> > > And, there might be two options in my mind by now to consider hotplug memory.
> > > Either giving an option for users to override "parange" as kernel
> > > param or providing the legacy way((memblock_end_of_DRAM() -
> > > memblock_start_of_DRAM()) when CONFIG_MEMORY_HOTPLUG is off.
> > > Users believe KASLR will work fine by enabling CONFIG_RANDOMIZE_BASE.
> > > In case of linear region randomization failure, I think at least users
> > > need to know about this failure.
> > > Can you share your thoughts on this please?
> > >
> >
> > Randomization of the linear map has always been a best effort thing,
> > so I don't think this is a big deal.
> >
> > I wouldn't object to the new behavior being conditional on
> > CONFIG_MEMORY_HOTPLUG, and fallback to the old behavior otherwise. But
> > ultimately, it will be up to the maintainers.
>
> Personally, given the confusion that linear map randomization seems to
> cause, I'd rather reduce the number of variables on which it depends.
>
> I also wonder whether it's actually useful at all...
>
> Will

I have thought of reducing parange until it fits into linear_region_size though.
+               if (range < 0) {
+                       pr_warn("parange(%d) does not fit into linear
region size\n", \
+                               id_aa64mmfr0_parange_to_phys_shift(parange));
+                       if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) {
+                               while (range < 0 && parange > 0) {
+                                       range = linear_region_size -
+
BIT(id_aa64mmfr0_parange_to_phys_shift(--parange));
+                               }
+                               pr_warn("smaller parange(%d) is chosen
for linear region randomization\n",
+
id_aa64mmfr0_parange_to_phys_shift(parange));
+                       } else {
+                               pr_warn("falling back to the range
considering on-boot DRAM size\n");
+                               range = linear_region_size -
+                                       (memblock_end_of_DRAM() -
+                                        memblock_start_of_DRAM());
+                       }
+               }

But, in a certain case, hotplug memory may get an address out of the
linear region at some point, as still SoC's parange can cover more
memory(ex. in this case, 1TiB).
So I think leaving a warning message for users might be the best
option. Then users feel it's time to move to a bigger address space to
resolve the issue.

               if (range < 0) {
+                       if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) {
+                               WARN(true, "linear region is not
randomized due to bigger parange\n");
+                       } else {
+                               range = linear_region_size -
+                                       (memblock_end_of_DRAM() -
+                                        memblock_start_of_DRAM());
+                       }
+               }
[PATCH v2] arm64: kaslr: warning linear region randomization on failure
Posted by kpark3469@gmail.com 9 months, 2 weeks ago
From: Keuno Park <keun-o.park@katim.com>

On systems using 4KB pages and having 39 VA_BITS, linear_region_size
gets 256GiB space. It was observed that some SoCs such as Qualcomm
QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
value to have minus as the variable range is s64, so that all the
calculations for randomizing linear address space are skipped.
As a result of this, the kernel's linear region is not randomized.
For hotplug memory users, kernel needs to inform that linear region
is not randomized. However, if CONFIG_MEMORY_HOTPLUG is turned off,
then kernel tries to fall back to the legacy way to randomize linear
region.

Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
Signed-off-by: Keuno Park <keun-o.park@katim.com>
---
 arch/arm64/mm/init.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 9c0b8d9558fc..848790a9e75e 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -290,6 +290,17 @@ void __init arm64_memblock_init(void)
 		s64 range = linear_region_size -
 			    BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
 
+		if (range < 0) {
+			if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) {
+				WARN(true, "linear region is not randomized due to bigger parange\n");
+			} else {
+				pr_warn("falling back to the range considering on-boot DRAM size\n");
+				range = linear_region_size -
+					(memblock_end_of_DRAM() -
+					 memblock_start_of_DRAM());
+			}
+		}
+
 		/*
 		 * If the size of the linear region exceeds, by a sufficient
 		 * margin, the size of the region that the physical memory can
-- 
2.34.1
Re: [PATCH] arm64: kaslr: consider parange is bigger than linear_region_size
Posted by Ard Biesheuvel 9 months, 3 weeks ago
On Mon, 24 Feb 2025 at 07:21, Keun-O Park <kpark3469@gmail.com> wrote:
>
> From: Keuno Park <keun-o.park@katim.com>
>
> On systems using 4KB pages and having 39 VA_BITS, linear_region_size
> gets 256GiB space. It was observed that some SoCs such as Qualcomm
> QCM8550 returns 40bits of PA range from MMFR0_EL1. This leads range
> value to have minus as the variable range is s64, so that all the
> calculations for randomizing linear address space are skpped.
> As a result of this, the kernel's linear region is not randomized.
> For this case, this patch sets the range by calculating memblock
> DRAM range to randomize the linear region of kernel.
>
> Change-Id: Ib29e45f44928937881d514fb87b4cac828b5a3f5
> Fixes: 97d6786e0669 ("arm64: mm: account for hotplug memory when randomizing the linear region")
> Signed-off-by: Keuno Park <keun-o.park@katim.com>
> ---
>  arch/arm64/mm/init.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 9c0b8d9558fc..2ee657e2d60f 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -290,6 +290,11 @@ void __init arm64_memblock_init(void)
>                 s64 range = linear_region_size -
>                             BIT(id_aa64mmfr0_parange_to_phys_shift(parange));
>
> +               if (range < 0) {
> +                       range = linear_region_size -
> +                               (memblock_end_of_DRAM() - memblock_start_of_DRAM());
> +               }
> +

Please explain how this ensures that hotplug memory still works as expected.