Skip to contentSkip to conversation

remoteproc: core: fix integer overflow in rproc_da_to_va() bounds check

PATCH Applied Atul Akella 2 participants 2 messages Oct 31 – Nov 5 Remote processor (remoteproc)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 remoteproc: core: fix integer overflow in rproc_da_to_va() bounds check

offset is calculated as da - carveout->da and stored in a 32 bit signed int, while da and carveout->da are both u64. For a sufficiently small da, the 64bit difference is truncated into the 32 bit int, bypassing the offset < 0 underflow check with a small positive value. Additionally, offset + len > carveout->len can itself overflow when offset and len are both large, providing a second bypass.

Rewrite the bounds check entirely in u64 arithmetic. Reject underflow before computing offset (da < carveout->da). Replace the addition-based overflow check with a subtraction-based one (len > carveout->len - offset) so no intermediate sum can wrap.

---
 drivers/remoteproc/remoteproc_core.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/remoteproc/remoteproc_core.c +6 -4
index 23f8539a99bd..d5fa9d23bd5c 100644
@@ -198,18 +198,20 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
 	}
 
 	list_for_each_entry(carveout, &rproc->carveouts, node) {
-		int offset = da - carveout->da;
+		u64 offset;
 
 		/*  Verify that carveout is allocated */
 		if (!carveout->va)
 			continue;
 
 		/* try next carveout if da is too small */
-		if (offset < 0)
+		if (da < carveout->da)
 			continue;
 
-		/* try next carveout if da is too large */
-		if (offset + len > carveout->len)
+		offset = da - carveout->da;
+
+		/* try next carveout if da or len is too large */
+		if (offset > carveout->len || len > carveout->len - offset)
 			continue;
 
 		ptr = carveout->va + offset;
Signature · 1 line
2.43.0
maintainer Applied
#1 lore raw
Quoted 13 lines · Atul Akella

offset is calculated as da - carveout->da and stored in a 32 bit signed int, while da and carveout->da are both u64. For a sufficiently small da, the 64bit difference is truncated into the 32 bit int, bypassing the offset < 0 underflow check with a small positive value. Additionally, offset + len > carveout->len can itself overflow when offset and len are both large, providing a second bypass.

Rewrite the bounds check entirely in u64 arithmetic. Reject underflow before computing offset (da < carveout->da). Replace the addition-based overflow check with a subtraction-based one (len > carveout->len - offset) so no intermediate sum can wrap.

Quoted 5 lines
---
 drivers/remoteproc/remoteproc_core.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

Applied.

Thanks,
Mathieu

Quoted 32 lines
drivers/remoteproc/remoteproc_core.c +6 -4
index 23f8539a99bd..d5fa9d23bd5c 100644
@@ -198,18 +198,20 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
 	}
 
 	list_for_each_entry(carveout, &rproc->carveouts, node) {
-		int offset = da - carveout->da;
+		u64 offset;
 
 		/*  Verify that carveout is allocated */
 		if (!carveout->va)
 			continue;
 
 		/* try next carveout if da is too small */
-		if (offset < 0)
+		if (da < carveout->da)
 			continue;
 
-		/* try next carveout if da is too large */
-		if (offset + len > carveout->len)
+		offset = da - carveout->da;
+
+		/* try next carveout if da or len is too large */
+		if (offset > carveout->len || len > carveout->len - offset)
 			continue;
 
 		ptr = carveout->va + offset;
Signature · 1 line
2.43.0