diff mbox series

[v3,1/3] xen/arm: Add memory overlap check for bootinfo.reserved_mem

Message ID 20230130040535.188236-2-Henry.Wang@arm.com (mailing list archive)
State Superseded
Headers show
Series Memory region overlap check in device tree | expand

Commit Message

Henry Wang Jan. 30, 2023, 4:05 a.m. UTC
As we are having more and more types of static region, and all of
these static regions are defined in bootinfo.reserved_mem, it is
necessary to add the overlap check of reserved memory regions in Xen,
because such check will help user to identify the misconfiguration in
the device tree at the early stage of boot time.

Currently we have 3 types of static region, namely
(1) static memory
(2) static heap
(3) static shared memory

(1) and (2) are parsed by the function `device_tree_get_meminfo()` and
(3) is parsed using its own logic. All of parsed information of these
types will be stored in `struct meminfo`.

Therefore, to unify the overlap checking logic for all of these types,
this commit firstly introduces a helper `meminfo_overlap_check()` and
a function `check_reserved_regions_overlap()` to check if an input
physical address range is overlapping with the existing memory regions
defined in bootinfo. After that, use `check_reserved_regions_overlap()`
in `device_tree_get_meminfo()` to do the overlap check of (1) and (2)
and replace the original overlap check of (3) with
`check_reserved_regions_overlap()`.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
---
v2 -> v3:
1. Use "[start, end]" format in printk error message.
2. Change the return type of helper functions to bool.
3. Use 'start' and 'size' in helper functions to describe a region.
v1 -> v2:
1. Split original `overlap_check()` to `meminfo_overlap_check()`.
2. Rework commit message.
---
 xen/arch/arm/bootfdt.c           | 13 +++++-----
 xen/arch/arm/include/asm/setup.h |  2 ++
 xen/arch/arm/setup.c             | 41 ++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 7 deletions(-)

Comments

Stefano Stabellini Jan. 30, 2023, 9:30 p.m. UTC | #1
On Mon, 30 Jan 2023, Henry Wang wrote:
> As we are having more and more types of static region, and all of
> these static regions are defined in bootinfo.reserved_mem, it is
> necessary to add the overlap check of reserved memory regions in Xen,
> because such check will help user to identify the misconfiguration in
> the device tree at the early stage of boot time.
> 
> Currently we have 3 types of static region, namely
> (1) static memory
> (2) static heap
> (3) static shared memory
> 
> (1) and (2) are parsed by the function `device_tree_get_meminfo()` and
> (3) is parsed using its own logic. All of parsed information of these
> types will be stored in `struct meminfo`.
> 
> Therefore, to unify the overlap checking logic for all of these types,
> this commit firstly introduces a helper `meminfo_overlap_check()` and
> a function `check_reserved_regions_overlap()` to check if an input
> physical address range is overlapping with the existing memory regions
> defined in bootinfo. After that, use `check_reserved_regions_overlap()`
> in `device_tree_get_meminfo()` to do the overlap check of (1) and (2)
> and replace the original overlap check of (3) with
> `check_reserved_regions_overlap()`.
> 
> Signed-off-by: Henry Wang <Henry.Wang@arm.com>

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> v2 -> v3:
> 1. Use "[start, end]" format in printk error message.
> 2. Change the return type of helper functions to bool.
> 3. Use 'start' and 'size' in helper functions to describe a region.
> v1 -> v2:
> 1. Split original `overlap_check()` to `meminfo_overlap_check()`.
> 2. Rework commit message.
> ---
>  xen/arch/arm/bootfdt.c           | 13 +++++-----
>  xen/arch/arm/include/asm/setup.h |  2 ++
>  xen/arch/arm/setup.c             | 41 ++++++++++++++++++++++++++++++++
>  3 files changed, 49 insertions(+), 7 deletions(-)
> 
> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
> index 0085c28d74..e2f6c7324b 100644
> --- a/xen/arch/arm/bootfdt.c
> +++ b/xen/arch/arm/bootfdt.c
> @@ -88,6 +88,9 @@ static int __init device_tree_get_meminfo(const void *fdt, int node,
>      for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
>      {
>          device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
> +        if ( mem == &bootinfo.reserved_mem &&
> +             check_reserved_regions_overlap(start, size) )
> +            return -EINVAL;
>          /* Some DT may describe empty bank, ignore them */
>          if ( !size )
>              continue;
> @@ -482,7 +485,9 @@ static int __init process_shm_node(const void *fdt, int node,
>                  return -EINVAL;
>              }
~  
> -            if ( (end <= mem->bank[i].start) || (paddr >= bank_end) )
> +            if ( check_reserved_regions_overlap(paddr, size) )
> +                return -EINVAL;
> +            else
>              {
>                  if ( strcmp(shm_id, mem->bank[i].shm_id) != 0 )
>                      continue;
> @@ -493,12 +498,6 @@ static int __init process_shm_node(const void *fdt, int node,
>                      return -EINVAL;
>                  }
>              }
> -            else
> -            {
> -                printk("fdt: shared memory region overlap with an existing entry %#"PRIpaddr" - %#"PRIpaddr"\n",
> -                        mem->bank[i].start, bank_end);
> -                return -EINVAL;
> -            }
>          }
>      }
>  
> diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
> index a926f30a2b..f0592370ea 100644
> --- a/xen/arch/arm/include/asm/setup.h
> +++ b/xen/arch/arm/include/asm/setup.h
> @@ -143,6 +143,8 @@ void fw_unreserved_regions(paddr_t s, paddr_t e,
>  size_t boot_fdt_info(const void *fdt, paddr_t paddr);
>  const char *boot_fdt_cmdline(const void *fdt);
>  
> +bool check_reserved_regions_overlap(paddr_t region_start, paddr_t region_size);
> +
>  struct bootmodule *add_boot_module(bootmodule_kind kind,
>                                     paddr_t start, paddr_t size, bool domU);
>  struct bootmodule *boot_module_find_by_kind(bootmodule_kind kind);
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 1f26f67b90..636604aafa 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -261,6 +261,32 @@ static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
>      cb(s, e);
>  }
>  
> +static bool __init meminfo_overlap_check(struct meminfo *meminfo,
> +                                         paddr_t region_start,
> +                                         paddr_t region_size)
> +{
> +    paddr_t bank_start = INVALID_PADDR, bank_end = 0;
> +    paddr_t region_end = region_start + region_size;
> +    unsigned int i, bank_num = meminfo->nr_banks;
> +
> +    for ( i = 0; i < bank_num; i++ )
> +    {
> +        bank_start = meminfo->bank[i].start;
> +        bank_end = bank_start + meminfo->bank[i].size;
> +
> +        if ( region_end <= bank_start || region_start >= bank_end )
> +            continue;
> +        else
> +        {
> +            printk("Region: [%#"PRIpaddr", %#"PRIpaddr"] overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr"]\n",
> +                   region_start, region_end, i, bank_start, bank_end);
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
>  void __init fw_unreserved_regions(paddr_t s, paddr_t e,
>                                    void (*cb)(paddr_t, paddr_t),
>                                    unsigned int first)
> @@ -271,7 +297,22 @@ void __init fw_unreserved_regions(paddr_t s, paddr_t e,
>          cb(s, e);
>  }
>  
> +/*
> + * Given an input physical address range, check if this range is overlapping
> + * with the existing reserved memory regions defined in bootinfo.
> + * Return true if the input physical address range is overlapping with any
> + * existing reserved memory regions, otherwise false.
> + */
> +bool __init check_reserved_regions_overlap(paddr_t region_start,
> +                                           paddr_t region_size)
> +{
> +    /* Check if input region is overlapping with bootinfo.reserved_mem banks */
> +    if ( meminfo_overlap_check(&bootinfo.reserved_mem,
> +                               region_start, region_size) )
> +        return true;
>  
> +    return false;
> +}
>  
>  struct bootmodule __init *add_boot_module(bootmodule_kind kind,
>                                            paddr_t start, paddr_t size,
> -- 
> 2.25.1
>
Julien Grall Jan. 30, 2023, 9:55 p.m. UTC | #2
Hi Henry,

On 30/01/2023 04:05, Henry Wang wrote:
> diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
> index a926f30a2b..f0592370ea 100644
> --- a/xen/arch/arm/include/asm/setup.h
> +++ b/xen/arch/arm/include/asm/setup.h
> @@ -143,6 +143,8 @@ void fw_unreserved_regions(paddr_t s, paddr_t e,
>   size_t boot_fdt_info(const void *fdt, paddr_t paddr);
>   const char *boot_fdt_cmdline(const void *fdt);
>   
> +bool check_reserved_regions_overlap(paddr_t region_start, paddr_t region_size);
> +
>   struct bootmodule *add_boot_module(bootmodule_kind kind,
>                                      paddr_t start, paddr_t size, bool domU);
>   struct bootmodule *boot_module_find_by_kind(bootmodule_kind kind);
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 1f26f67b90..636604aafa 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -261,6 +261,32 @@ static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
>       cb(s, e);
>   }
>   
> +static bool __init meminfo_overlap_check(struct meminfo *meminfo,
> +                                         paddr_t region_start,
> +                                         paddr_t region_size)

So the interface looks nicer but now...

> +{
> +    paddr_t bank_start = INVALID_PADDR, bank_end = 0;
> +    paddr_t region_end = region_start + region_size;
> +    unsigned int i, bank_num = meminfo->nr_banks;
> +
> +    for ( i = 0; i < bank_num; i++ )
> +    {
> +        bank_start = meminfo->bank[i].start;
> +        bank_end = bank_start + meminfo->bank[i].size;
> +
> +        if ( region_end <= bank_start || region_start >= bank_end )

... it clearly shows how this check would be wrong when either the bank 
or the region is at the end of the address space. You may say it doesn't 
overlap when it could (e.g. when region_end < region_start).

That said, unless we rework 'bank', we would not properly solve the 
problem. But that's likely a bigger piece of work and not something I 
would request.

So for now, I would suggest to add a comment. Stefano, what do you think?

> +            continue;
> +        else
> +        {
> +            printk("Region: [%#"PRIpaddr", %#"PRIpaddr"] overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr"]\n",

']' usually mean inclusive. But here, 'end' is exclusive. So you want '['.

This could be fixed on commit.


BTW, the same comments applies for the second patch.

> +                   region_start, region_end, i, bank_start, bank_end);
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
>   void __init fw_unreserved_regions(paddr_t s, paddr_t e,
>                                     void (*cb)(paddr_t, paddr_t),
>                                     unsigned int first)
> @@ -271,7 +297,22 @@ void __init fw_unreserved_regions(paddr_t s, paddr_t e,
>           cb(s, e);
>   }
>   
> +/*
> + * Given an input physical address range, check if this range is overlapping
> + * with the existing reserved memory regions defined in bootinfo.
> + * Return true if the input physical address range is overlapping with any
> + * existing reserved memory regions, otherwise false.
> + */
> +bool __init check_reserved_regions_overlap(paddr_t region_start,
> +                                           paddr_t region_size)
> +{
> +    /* Check if input region is overlapping with bootinfo.reserved_mem banks */
> +    if ( meminfo_overlap_check(&bootinfo.reserved_mem,
> +                               region_start, region_size) )
> +        return true;
>   
> +    return false;
> +}
>   
>   struct bootmodule __init *add_boot_module(bootmodule_kind kind,
>                                             paddr_t start, paddr_t size,

Cheers,
Henry Wang Jan. 31, 2023, 2:25 a.m. UTC | #3
Hi Julien,

> -----Original Message-----
> From: Julien Grall <julien@xen.org>
> Subject: Re: [PATCH v3 1/3] xen/arm: Add memory overlap check for
> bootinfo.reserved_mem
> 
> Hi Henry,
> 
> > +{
> > +    paddr_t bank_start = INVALID_PADDR, bank_end = 0;
> > +    paddr_t region_end = region_start + region_size;
> > +    unsigned int i, bank_num = meminfo->nr_banks;
> > +
> > +    for ( i = 0; i < bank_num; i++ )
> > +    {
> > +        bank_start = meminfo->bank[i].start;
> > +        bank_end = bank_start + meminfo->bank[i].size;
> > +
> > +        if ( region_end <= bank_start || region_start >= bank_end )
> 
> ... it clearly shows how this check would be wrong when either the bank
> or the region is at the end of the address space. You may say it doesn't
> overlap when it could (e.g. when region_end < region_start).

Here do you mean if the region is at the end of the addr space,
"region_start + region_end" will overflow and cause
region_end < region_start? If so...

> 
> That said, unless we rework 'bank', we would not properly solve the
> problem. But that's likely a bigger piece of work and not something I
> would request.
> 
> So for now, I would suggest to add a comment. Stefano, what do you think?

...I am not really sure if simply adding a comment here would help,
because when the overflow happens, we are already doomed because
of the messed-up device tree.

Would adding a `BUG_ON(region_end < region_start)` make sense to you?

> 
> > +            continue;
> > +        else
> > +        {
> > +            printk("Region: [%#"PRIpaddr", %#"PRIpaddr"] overlapping with
> bank[%u]: [%#"PRIpaddr", %#"PRIpaddr"]\n",
> 
> ']' usually mean inclusive. But here, 'end' is exclusive. So you want '['.

Oh, now I understand the misunderstanding in our communication in v1:
I didn't know '[' means exclusive because I was educated to use ')' [1] so I
thought you meant inclusive. Sorry for this.

To keep consistency, may I use ')' here? Because I think this is the current
way in the code base, for example see:
xen/include/xen/numa.h L99: [*start, *end)
xen/drivers/passthrough/amd/iommu_acpi.c L177: overlap [%lx,%lx)

> 
> This could be fixed on commit.
> 
> BTW, the same comments applies for the second patch.

I will fix this patch and #2 in v4.

[1] https://en.wikipedia.org/wiki/Interval_(mathematics)#Including_or_excluding_endpoints

Kind regards,
Henry

> 
> Cheers,
> 
> --
> Julien Grall
Julien Grall Jan. 31, 2023, 9:19 a.m. UTC | #4
On 31/01/2023 02:25, Henry Wang wrote:
> Hi Julien,
> 
>> -----Original Message-----
>> From: Julien Grall <julien@xen.org>
>> Subject: Re: [PATCH v3 1/3] xen/arm: Add memory overlap check for
>> bootinfo.reserved_mem
>>
>> Hi Henry,
>>
>>> +{
>>> +    paddr_t bank_start = INVALID_PADDR, bank_end = 0;
>>> +    paddr_t region_end = region_start + region_size;
>>> +    unsigned int i, bank_num = meminfo->nr_banks;
>>> +
>>> +    for ( i = 0; i < bank_num; i++ )
>>> +    {
>>> +        bank_start = meminfo->bank[i].start;
>>> +        bank_end = bank_start + meminfo->bank[i].size;
>>> +
>>> +        if ( region_end <= bank_start || region_start >= bank_end )
>>
>> ... it clearly shows how this check would be wrong when either the bank
>> or the region is at the end of the address space. You may say it doesn't
>> overlap when it could (e.g. when region_end < region_start).
> 
> Here do you mean if the region is at the end of the addr space,
> "region_start + region_end" will overflow and cause
> region_end < region_start? If so...

Yes.

> 
>>
>> That said, unless we rework 'bank', we would not properly solve the
>> problem. But that's likely a bigger piece of work and not something I
>> would request.
>>
>> So for now, I would suggest to add a comment. Stefano, what do you think?
> 
> ...I am not really sure if simply adding a comment here would help,
> because when the overflow happens, we are already doomed because
> of the messed-up device tree.

Not necessarily. This could happen if the region is right at the top of 
the address (e.g. finishing at 2^64 - 1). As the 'end' is exclusive, 
then it would be equal to 0.

I think this is less likely for arm64, but this could happen for 32-bit 
Arm as we will allow the admin to reduce paddr_t from 64-bit to 32-bit.

> 
> Would adding a `BUG_ON(region_end < region_start)` make sense to you?
No for the reason I stated above.

> 
>>
>>> +            continue;
>>> +        else
>>> +        {
>>> +            printk("Region: [%#"PRIpaddr", %#"PRIpaddr"] overlapping with
>> bank[%u]: [%#"PRIpaddr", %#"PRIpaddr"]\n",
>>
>> ']' usually mean inclusive. But here, 'end' is exclusive. So you want '['.
> 
> Oh, now I understand the misunderstanding in our communication in v1:
> I didn't know '[' means exclusive because I was educated to use ')' [1] so I
> thought you meant inclusive. Sorry for this.

No worries. That might be only me using [ and ) interchangeably :).

> 
> To keep consistency, may I use ')' here? Because I think this is the current
> way in the code base, for example see:
> xen/include/xen/numa.h L99: [*start, *end)
> xen/drivers/passthrough/amd/iommu_acpi.c L177: overlap [%lx,%lx)

I am fine with that.

>> BTW, the same comments applies for the second patch.
> 
> I will fix this patch and #2 in v4.

I am happy to deal with it on commit if you want.

Cheers,
Henry Wang Jan. 31, 2023, 9:30 a.m. UTC | #5
Hi Julien,

> -----Original Message-----
> From: Julien Grall <julien@xen.org>
> Subject: Re: [PATCH v3 1/3] xen/arm: Add memory overlap check for
> bootinfo.reserved_mem
> > I will fix this patch and #2 in v4.
> 
> I am happy to deal with it on commit if you want.

Including adding the comment for both patches? This would be wonderful
and very nice of you to do that. But if your time is limited I am also more
than happy to respin the patch (probably even with Stefano's Reviewed-by
tag if he is ok with it) to reduce your burden. That said, if I need to respin the
patch, it would be good to get some hints about the wording of the comments
to avoid another v+1 just because of my inaccurate wording :) Thanks very
much!

Kind regards,
Henry

> 
> Cheers,
> 
> --
> Julien Grall
Julien Grall Jan. 31, 2023, 9:59 a.m. UTC | #6
On 31/01/2023 09:30, Henry Wang wrote:
> Hi Julien,
> 
>> -----Original Message-----
>> From: Julien Grall <julien@xen.org>
>> Subject: Re: [PATCH v3 1/3] xen/arm: Add memory overlap check for
>> bootinfo.reserved_mem
>>> I will fix this patch and #2 in v4.
>>
>> I am happy to deal with it on commit if you want.
> 
> Including adding the comment for both patches? This would be wonderful
> and very nice of you to do that. But if your time is limited I am also more
> than happy to respin the patch (probably even with Stefano's Reviewed-by
> tag if he is ok with it) to reduce your burden. That said, if I need to respin the
> patch, it would be good to get some hints about the wording of the comments
> to avoid another v+1 just because of my inaccurate wording :)

Good idea. My suggestion would be:

TODO: '*_end' could be 0 if the bank/region is at the end of the 
physical address space. This is for now not handled as it requires more 
rework.

Cheers,
diff mbox series

Patch

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 0085c28d74..e2f6c7324b 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -88,6 +88,9 @@  static int __init device_tree_get_meminfo(const void *fdt, int node,
     for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
     {
         device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
+        if ( mem == &bootinfo.reserved_mem &&
+             check_reserved_regions_overlap(start, size) )
+            return -EINVAL;
         /* Some DT may describe empty bank, ignore them */
         if ( !size )
             continue;
@@ -482,7 +485,9 @@  static int __init process_shm_node(const void *fdt, int node,
                 return -EINVAL;
             }
 
-            if ( (end <= mem->bank[i].start) || (paddr >= bank_end) )
+            if ( check_reserved_regions_overlap(paddr, size) )
+                return -EINVAL;
+            else
             {
                 if ( strcmp(shm_id, mem->bank[i].shm_id) != 0 )
                     continue;
@@ -493,12 +498,6 @@  static int __init process_shm_node(const void *fdt, int node,
                     return -EINVAL;
                 }
             }
-            else
-            {
-                printk("fdt: shared memory region overlap with an existing entry %#"PRIpaddr" - %#"PRIpaddr"\n",
-                        mem->bank[i].start, bank_end);
-                return -EINVAL;
-            }
         }
     }
 
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index a926f30a2b..f0592370ea 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -143,6 +143,8 @@  void fw_unreserved_regions(paddr_t s, paddr_t e,
 size_t boot_fdt_info(const void *fdt, paddr_t paddr);
 const char *boot_fdt_cmdline(const void *fdt);
 
+bool check_reserved_regions_overlap(paddr_t region_start, paddr_t region_size);
+
 struct bootmodule *add_boot_module(bootmodule_kind kind,
                                    paddr_t start, paddr_t size, bool domU);
 struct bootmodule *boot_module_find_by_kind(bootmodule_kind kind);
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 1f26f67b90..636604aafa 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -261,6 +261,32 @@  static void __init dt_unreserved_regions(paddr_t s, paddr_t e,
     cb(s, e);
 }
 
+static bool __init meminfo_overlap_check(struct meminfo *meminfo,
+                                         paddr_t region_start,
+                                         paddr_t region_size)
+{
+    paddr_t bank_start = INVALID_PADDR, bank_end = 0;
+    paddr_t region_end = region_start + region_size;
+    unsigned int i, bank_num = meminfo->nr_banks;
+
+    for ( i = 0; i < bank_num; i++ )
+    {
+        bank_start = meminfo->bank[i].start;
+        bank_end = bank_start + meminfo->bank[i].size;
+
+        if ( region_end <= bank_start || region_start >= bank_end )
+            continue;
+        else
+        {
+            printk("Region: [%#"PRIpaddr", %#"PRIpaddr"] overlapping with bank[%u]: [%#"PRIpaddr", %#"PRIpaddr"]\n",
+                   region_start, region_end, i, bank_start, bank_end);
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void __init fw_unreserved_regions(paddr_t s, paddr_t e,
                                   void (*cb)(paddr_t, paddr_t),
                                   unsigned int first)
@@ -271,7 +297,22 @@  void __init fw_unreserved_regions(paddr_t s, paddr_t e,
         cb(s, e);
 }
 
+/*
+ * Given an input physical address range, check if this range is overlapping
+ * with the existing reserved memory regions defined in bootinfo.
+ * Return true if the input physical address range is overlapping with any
+ * existing reserved memory regions, otherwise false.
+ */
+bool __init check_reserved_regions_overlap(paddr_t region_start,
+                                           paddr_t region_size)
+{
+    /* Check if input region is overlapping with bootinfo.reserved_mem banks */
+    if ( meminfo_overlap_check(&bootinfo.reserved_mem,
+                               region_start, region_size) )
+        return true;
 
+    return false;
+}
 
 struct bootmodule __init *add_boot_module(bootmodule_kind kind,
                                           paddr_t start, paddr_t size,