diff options
author | Thomas Weißschuh <thomas.weissschuh@linutronix.de> | 2024-09-06 14:25:19 +0200 |
---|---|---|
committer | Rob Herring (Arm) <robh@kernel.org> | 2024-09-13 14:00:52 -0500 |
commit | 1a52a094c2f0821860d9ce15fffe01103a146f1f (patch) | |
tree | 4403d7cd86e6b2c80bc31159cc29816f1fabe291 /drivers/of | |
parent | 22e2bf1214ff50981c7e056970241a36ab1f3d14 (diff) | |
download | linux-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.c | 43 |
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); } /** |