[PATCH] of: address: Report error on resource bounds overflow

Thomas Weißschuh posted 1 patch 1 year, 3 months ago
drivers/of/address.c | 5 +++++
1 file changed, 5 insertions(+)
[PATCH] of: address: Report error on resource bounds overflow
Posted by Thomas Weißschuh 1 year, 3 months ago
The members "start" and "end" of struct resource are of type
"resource_size_t" which can be 32bit wide.
Values read from OF however are always 64bit wide.
Avoid silently truncating the value and instead return an error value.

This can happen on real systems when the DT was created for a
PAE-enabled kernel and a non-PAE kernel is actually running.
For example with an arm defconfig and "qemu-system-arm -M virt".

Link: https://bugs.launchpad.net/qemu/+bug/1790975
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Tested-by: Nam Cao <namcao@linutronix.de>
Reviewed-by: Nam Cao <namcao@linutronix.de>
---
 drivers/of/address.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index d669ce25b5f9..7e59283a4472 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -8,6 +8,7 @@
 #include <linux/logic_pio.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/overflow.h>
 #include <linux/pci.h>
 #include <linux/pci_regs.h>
 #include <linux/sizes.h>
@@ -1061,7 +1062,11 @@ static int __of_address_to_resource(struct device_node *dev, int index, int bar_
 	if (of_mmio_is_nonposted(dev))
 		flags |= IORESOURCE_MEM_NONPOSTED;
 
+	if (overflows_type(taddr, r->start))
+		return -EOVERFLOW;
 	r->start = taddr;
+	if (overflows_type(taddr + size - 1, r->end))
+		return -EOVERFLOW;
 	r->end = taddr + size - 1;
 	r->flags = flags;
 	r->name = name ? name : dev->full_name;

---
base-commit: 67784a74e258a467225f0e68335df77acd67b7ab
change-id: 20240904-of-resource-overflow-378ea11dec8b

Best regards,
-- 
Thomas Weißschuh <thomas.weissschuh@linutronix.de>

Re: [PATCH] of: address: Report error on resource bounds overflow
Posted by Rob Herring 1 year, 3 months ago
On Thu, Sep 5, 2024 at 2:46 AM Thomas Weißschuh
<thomas.weissschuh@linutronix.de> wrote:
>
> The members "start" and "end" of struct resource are of type
> "resource_size_t" which can be 32bit wide.
> Values read from OF however are always 64bit wide.
> Avoid silently truncating the value and instead return an error value.
>
> This can happen on real systems when the DT was created for a
> PAE-enabled kernel and a non-PAE kernel is actually running.
> For example with an arm defconfig and "qemu-system-arm -M virt".

A nice follow-up would be to make of_pci_range_to_resource() use
overflows_type() as well instead of open coding it.

> Link: https://bugs.launchpad.net/qemu/+bug/1790975
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
> Tested-by: Nam Cao <namcao@linutronix.de>
> Reviewed-by: Nam Cao <namcao@linutronix.de>
> ---
>  drivers/of/address.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index d669ce25b5f9..7e59283a4472 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -8,6 +8,7 @@
>  #include <linux/logic_pio.h>
>  #include <linux/module.h>
>  #include <linux/of_address.h>
> +#include <linux/overflow.h>
>  #include <linux/pci.h>
>  #include <linux/pci_regs.h>
>  #include <linux/sizes.h>
> @@ -1061,7 +1062,11 @@ static int __of_address_to_resource(struct device_node *dev, int index, int bar_
>         if (of_mmio_is_nonposted(dev))
>                 flags |= IORESOURCE_MEM_NONPOSTED;
>
> +       if (overflows_type(taddr, r->start))
> +               return -EOVERFLOW;
>         r->start = taddr;

It looks odd that "r->start" is used before it is set, but I guess
overflows_type isn't using the value and the compiler would warn
otherwise.

Applied, thanks.

Rob
Re: [PATCH] of: address: Report error on resource bounds overflow
Posted by Thomas Weißschuh 1 year, 3 months ago
On Thu, Sep 05, 2024 at 08:15:40AM GMT, Rob Herring wrote:
> On Thu, Sep 5, 2024 at 2:46 AM Thomas Weißschuh
> <thomas.weissschuh@linutronix.de> wrote:
> >
> > The members "start" and "end" of struct resource are of type
> > "resource_size_t" which can be 32bit wide.
> > Values read from OF however are always 64bit wide.
> > Avoid silently truncating the value and instead return an error value.
> >
> > This can happen on real systems when the DT was created for a
> > PAE-enabled kernel and a non-PAE kernel is actually running.
> > For example with an arm defconfig and "qemu-system-arm -M virt".
> 
> A nice follow-up would be to make of_pci_range_to_resource() use
> overflows_type() as well instead of open coding it.

Good catch.

There are some differences though, it
* returns -EINVAL on overflow instead of -EOVERFLOW
* sets ->start and ->end to OF_BAD_ADDR on overflow
* does not check ->end for overflow

I don't have much experience with OF, so I'm not sure which of these are
important and if overflow checks on intermediate calculations are also
necessary.
Re: [PATCH] of: address: Report error on resource bounds overflow
Posted by Rob Herring 1 year, 3 months ago
On Thu, Sep 5, 2024 at 8:41 AM Thomas Weißschuh
<thomas.weissschuh@linutronix.de> wrote:
>
> On Thu, Sep 05, 2024 at 08:15:40AM GMT, Rob Herring wrote:
> > On Thu, Sep 5, 2024 at 2:46 AM Thomas Weißschuh
> > <thomas.weissschuh@linutronix.de> wrote:
> > >
> > > The members "start" and "end" of struct resource are of type
> > > "resource_size_t" which can be 32bit wide.
> > > Values read from OF however are always 64bit wide.
> > > Avoid silently truncating the value and instead return an error value.
> > >
> > > This can happen on real systems when the DT was created for a
> > > PAE-enabled kernel and a non-PAE kernel is actually running.
> > > For example with an arm defconfig and "qemu-system-arm -M virt".
> >
> > A nice follow-up would be to make of_pci_range_to_resource() use
> > overflows_type() as well instead of open coding it.
>
> Good catch.
>
> There are some differences though, it
> * returns -EINVAL on overflow instead of -EOVERFLOW

I think that is safe to change. I don't see any cases looking at the
specific errno. Note that of_range_to_resource() kerneldoc would need
updating too.

> * sets ->start and ->end to OF_BAD_ADDR on overflow

Don't need to do that. No user accesses the resource on error.

> * does not check ->end for overflow

Obviously we want to do that.

Rob