diff mbox series

[v2,4/7] xen/device-tree: Fix bootfdt.c to tolerate 0 reserved regions

Message ID 1c6f0f94f4ea2b773f960d88bd02e2168ac28abb.1702607884.git.sanastasio@raptorengineering.com (mailing list archive)
State New
Headers show
Series Early Boot Allocation on Power | expand

Commit Message

Shawn Anastasio Dec. 15, 2023, 2:43 a.m. UTC
The early_print_info routine in bootfdt.c incorrectly stores the result
of a call to fdt_num_mem_rsv() in an unsigned int, which results in the
negative error code being interpreted incorrectly in a subsequent loop
in the case where the device tree does not contain any memory reserve
map entries.

Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
---
 xen/common/device-tree/bootfdt.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Julien Grall Jan. 9, 2024, 6:14 p.m. UTC | #1
(+ Stefano)

Hi Shawn,

On 15/12/2023 02:43, Shawn Anastasio wrote:
> The early_print_info routine in bootfdt.c incorrectly stores the result
> of a call to fdt_num_mem_rsv() in an unsigned int, which results in the
> negative error code being interpreted incorrectly in a subsequent loop
> in the case where the device tree does not contain any memory reserve
> map entries.

I have some trouble to reconciliate the code with your explanation. 
Looking at the implementation fdt_num_mem_rsv() should return 0 if there 
are no reserved regions. A negative value would only be returned if the 
device-tree is malformated.

Do you have a Device-Tree where the issue occurs?

That said, I agree that the code could be hardened.

> 
> Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
> ---
>   xen/common/device-tree/bootfdt.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c
> index ae9fa1e3d6..796ac01c18 100644
> --- a/xen/common/device-tree/bootfdt.c
> +++ b/xen/common/device-tree/bootfdt.c
> @@ -466,7 +466,8 @@ static void __init early_print_info(void)
>       struct meminfo *mem_resv = &bootinfo.reserved_mem;
>       struct bootmodules *mods = &bootinfo.modules;
>       struct bootcmdlines *cmds = &bootinfo.cmdlines;
> -    unsigned int i, j, nr_rsvd;
> +    unsigned int i, j;
> +    int nr_rsvd;
>   
>       for ( i = 0; i < mi->nr_banks; i++ )
>           printk("RAM: %"PRIpaddr" - %"PRIpaddr"\n",
> @@ -481,7 +482,7 @@ static void __init early_print_info(void)
>                   boot_module_kind_as_string(mods->module[i].kind));
>   
>       nr_rsvd = fdt_num_mem_rsv(device_tree_flattened);

If I am correct above, then I think we should panic() rather than trying 
to continue with a buggy DT.

> -    for ( i = 0; i < nr_rsvd; i++ )
> +    for ( i = 0; nr_rsvd > 0 && i < nr_rsvd; i++ )
>       {
>           paddr_t s, e;
>   

Cheers,
Michal Orzel Jan. 10, 2024, 8:15 a.m. UTC | #2
On 09/01/2024 19:14, Julien Grall wrote:
> 
> 
> (+ Stefano)
> 
> Hi Shawn,
> 
> On 15/12/2023 02:43, Shawn Anastasio wrote:
>> The early_print_info routine in bootfdt.c incorrectly stores the result
>> of a call to fdt_num_mem_rsv() in an unsigned int, which results in the
>> negative error code being interpreted incorrectly in a subsequent loop
>> in the case where the device tree does not contain any memory reserve
>> map entries.
> 
> I have some trouble to reconciliate the code with your explanation.
> Looking at the implementation fdt_num_mem_rsv() should return 0 if there
> are no reserved regions. A negative value would only be returned if the
> device-tree is malformated.
I agree with Julien. The function takes an offset to reserve map and grabs blocks of type fdt_reserve_entry
from there. In case of no regions, there will be one entry with addr/size 0 which always acts as a termination region.
The only way to return < 0 is when you have a buggy FDT.

> 
> Do you have a Device-Tree where the issue occurs?
> 
> That said, I agree that the code could be hardened.
> 
>>
>> Signed-off-by: Shawn Anastasio <sanastasio@raptorengineering.com>
>> ---
>>   xen/common/device-tree/bootfdt.c | 5 +++--
>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c
>> index ae9fa1e3d6..796ac01c18 100644
>> --- a/xen/common/device-tree/bootfdt.c
>> +++ b/xen/common/device-tree/bootfdt.c
>> @@ -466,7 +466,8 @@ static void __init early_print_info(void)
>>       struct meminfo *mem_resv = &bootinfo.reserved_mem;
>>       struct bootmodules *mods = &bootinfo.modules;
>>       struct bootcmdlines *cmds = &bootinfo.cmdlines;
>> -    unsigned int i, j, nr_rsvd;
>> +    unsigned int i, j;
>> +    int nr_rsvd;
>>
>>       for ( i = 0; i < mi->nr_banks; i++ )
>>           printk("RAM: %"PRIpaddr" - %"PRIpaddr"\n",
>> @@ -481,7 +482,7 @@ static void __init early_print_info(void)
>>                   boot_module_kind_as_string(mods->module[i].kind));
>>
>>       nr_rsvd = fdt_num_mem_rsv(device_tree_flattened);
> 
> If I am correct above, then I think we should panic() rather than trying
> to continue with a buggy DT.
+1. Furthermore, we already call panic in such case in dt_unreserved_regions().

> 
>> -    for ( i = 0; i < nr_rsvd; i++ )
>> +    for ( i = 0; nr_rsvd > 0 && i < nr_rsvd; i++ )
>>       {
>>           paddr_t s, e;
>>
> 
> Cheers,
> 
> --
> Julien Grall
> 

~Michal
Shawn Anastasio Jan. 11, 2024, 10:56 p.m. UTC | #3
Hi Julien

On 1/9/24 12:14 PM, Julien Grall wrote:
> (+ Stefano)
> 
> Hi Shawn,
> 
> On 15/12/2023 02:43, Shawn Anastasio wrote:
>> The early_print_info routine in bootfdt.c incorrectly stores the result
>> of a call to fdt_num_mem_rsv() in an unsigned int, which results in the
>> negative error code being interpreted incorrectly in a subsequent loop
>> in the case where the device tree does not contain any memory reserve
>> map entries.
> 
> I have some trouble to reconciliate the code with your explanation.
> Looking at the implementation fdt_num_mem_rsv() should return 0 if there
> are no reserved regions. A negative value would only be returned if the
> device-tree is malformated.
> 
> Do you have a Device-Tree where the issue occurs?
> 
> That said, I agree that the code could be hardened.
>

After reading your comment, I looked into it again and it appears you're
right. It turns out that I was hitting this issue not because my device
tree had 0 entries or was corrupt, but because the function was being
called with an invalid device tree pointer to begin with!

Specifically, bootfdt.c:early_print_info calls fdt_num_mem_rsv using the
global `device_tree_flattened` variable which PPC's setup.c did not
properly initialize:

    nr_rsvd = fdt_num_mem_rsv(device_tree_flattened);

Thanks for the sanity check. I'll fix this in the next revision of the
patchset.

Despite my misunderstanding of how the bug was triggered in my case, it
definitely is still something that should be fixed. Following yours and
Michal's suggestion, I'll change the patch to panic() instead and submit
a follow-up (likely standalone and not as a part of this series).

> Cheers,

Thanks,
Shawn
diff mbox series

Patch

diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c
index ae9fa1e3d6..796ac01c18 100644
--- a/xen/common/device-tree/bootfdt.c
+++ b/xen/common/device-tree/bootfdt.c
@@ -466,7 +466,8 @@  static void __init early_print_info(void)
     struct meminfo *mem_resv = &bootinfo.reserved_mem;
     struct bootmodules *mods = &bootinfo.modules;
     struct bootcmdlines *cmds = &bootinfo.cmdlines;
-    unsigned int i, j, nr_rsvd;
+    unsigned int i, j;
+    int nr_rsvd;
 
     for ( i = 0; i < mi->nr_banks; i++ )
         printk("RAM: %"PRIpaddr" - %"PRIpaddr"\n",
@@ -481,7 +482,7 @@  static void __init early_print_info(void)
                 boot_module_kind_as_string(mods->module[i].kind));
 
     nr_rsvd = fdt_num_mem_rsv(device_tree_flattened);
-    for ( i = 0; i < nr_rsvd; i++ )
+    for ( i = 0; nr_rsvd > 0 && i < nr_rsvd; i++ )
     {
         paddr_t s, e;