]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
cmd: read: fix unsigned overflow bypassing range check
authorNaveen Kumar Chaudhary <naveen.osdev@gmail.com>
Wed, 8 Jul 2026 14:33:04 +0000 (20:03 +0530)
committerTom Rini <trini@konsulko.com>
Tue, 21 Jul 2026 19:52:50 +0000 (13:52 -0600)
The bounds check in do_rw() was written as:

    if (cnt + blk > limit)

with cnt and blk declared as uint (unsigned int) and limit as ulong.
C's usual arithmetic conversions are applied per binary operator, so
"cnt + blk" is evaluated entirely in unsigned int and wraps modulo
2^32 before the result is widened for the comparison against limit.
With cnt = 0xFFFFFFFF and blk = 1 the sum wraps to 0 and the guard
passes, allowing blk_dread()/blk_dwrite() to be issued with a 4 GiB
transfer count that runs past the partition (or, when no partition
is selected, the entire device).

Rewrite the check as two comparisons that do not overflow:

    if (blk > limit || cnt > limit - blk)

The subtraction is performed in ulong (limit's type), so no truncation
occurs, and the two sub-conditions cover both "start block past end"
and "count would push us past end" failure modes.

Signed-off-by: Naveen Kumar Chaudhary <naveen.osdev@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
cmd/read.c

index 8e21f004423e824dd619882b9f910a082950b41a..efc255ce85d591452a1e8284426d276d15abd094 100644 (file)
@@ -46,7 +46,7 @@ do_rw(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
                limit = ~0;
        }
 
-       if (cnt + blk > limit) {
+       if (blk > limit || cnt > limit - blk) {
                printf("%s out of range\n", cmdtp->name);
                unmap_sysmem(ptr);
                return 1;