summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorThomas Weißschuh <thomas.weissschuh@linutronix.de>2024-09-06 14:25:19 +0200
committerRob Herring (Arm) <robh@kernel.org>2024-09-13 14:00:52 -0500
commit1a52a094c2f0821860d9ce15fffe01103a146f1f (patch)
tree4403d7cd86e6b2c80bc31159cc29816f1fabe291 /drivers/of
parent22e2bf1214ff50981c7e056970241a36ab1f3d14 (diff)
downloadlinux-stable-1a52a094c2f0821860d9ce15fffe01103a146f1f.tar.gz
linux-stable-1a52a094c2f0821860d9ce15fffe01103a146f1f.tar.bz2
linux-stable-1a52a094c2f0821860d9ce15fffe01103a146f1f.zip
of: address: Unify resource bounds overflow checking
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. Refactor the diff overflow checks into a helper function. Also extend the checks to validate each calculation step. Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de> Link: https://lore.kernel.org/r/20240906-of-address-overflow-v1-1-19567aaa61da@linutronix.de [robh: Fix to not return error on 0 sized resource] Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/address.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 7e59283a4472..286f0c161e33 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -198,6 +198,23 @@ static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
#endif /* CONFIG_PCI */
+static int __of_address_resource_bounds(struct resource *r, u64 start, u64 size)
+{
+ u64 end = start;
+
+ if (overflows_type(start, r->start))
+ return -EOVERFLOW;
+ if (size && check_add_overflow(end, size - 1, &end))
+ return -EOVERFLOW;
+ if (overflows_type(end, r->end))
+ return -EOVERFLOW;
+
+ r->start = start;
+ r->end = end;
+
+ return 0;
+}
+
/*
* of_pci_range_to_resource - Create a resource from an of_pci_range
* @range: the PCI range that describes the resource
@@ -216,6 +233,7 @@ static u64 of_bus_pci_map(__be32 *addr, const __be32 *range, int na, int ns,
int of_pci_range_to_resource(struct of_pci_range *range,
struct device_node *np, struct resource *res)
{
+ u64 start;
int err;
res->flags = range->flags;
res->parent = res->child = res->sibling = NULL;
@@ -232,18 +250,11 @@ int of_pci_range_to_resource(struct of_pci_range *range,
err = -EINVAL;
goto invalid_range;
}
- res->start = port;
+ start = port;
} else {
- if ((sizeof(resource_size_t) < 8) &&
- upper_32_bits(range->cpu_addr)) {
- err = -EINVAL;
- goto invalid_range;
- }
-
- res->start = range->cpu_addr;
+ start = range->cpu_addr;
}
- res->end = res->start + range->size - 1;
- return 0;
+ return __of_address_resource_bounds(res, start, range->size);
invalid_range:
res->start = (resource_size_t)OF_BAD_ADDR;
@@ -259,8 +270,8 @@ EXPORT_SYMBOL(of_pci_range_to_resource);
* @res: pointer to a valid resource that will be updated to
* reflect the values contained in the range.
*
- * Returns ENOENT if the entry is not found or EINVAL if the range cannot be
- * converted to resource.
+ * Returns -ENOENT if the entry is not found or -EOVERFLOW if the range
+ * cannot be converted to resource.
*/
int of_range_to_resource(struct device_node *np, int index, struct resource *res)
{
@@ -1062,16 +1073,10 @@ 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;
- return 0;
+ return __of_address_resource_bounds(r, taddr, size);
}
/**