Hi,

tobias@ spotted this one a few months ago when reviewing a different
diff of mine.

Casting the size given to malloc(3) here causes it to wrap if our block
sizes are large enough, and then dd(1) misbehaves, at least on 64-bit
platforms:

# dd bs=$(((1 << 31) + 1)) cbs=$((1 << 31)) conv=ascii if=/dev/zero 
of=/dev/null count=1
dd: /dev/random: Bad address

The block sizes sum to 1 when cast and malloc(3) breaks us off a byte.
read(2) then sees that it would be writing outside the valid address
space and fails.

Fix attached.

Maybe pedantic, but should we also be checking for addition overflow?  OpenBSD
is fine -- those additions will not overflow, as we check prior to this point
that all block sizes are <= SSIZE_MAX.  But the standard doesn't guarantee
that SSIZE_MAX * 2 < SIZE_MAX.  Are such considerations left to the porter?

... ok as-is?

-Scott

Index: bin/dd/dd.c
===================================================================
RCS file: /cvs/src/bin/dd/dd.c,v
retrieving revision 1.24
diff -u -p -r1.24 dd.c
--- bin/dd/dd.c 13 Aug 2017 02:06:42 -0000      1.24
+++ bin/dd/dd.c 20 Jul 2018 23:44:12 -0000
@@ -136,10 +136,14 @@ setup(void)
                if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
                        err(1, "input buffer");
                out.db = in.db;
-       } else if ((in.db =
-           malloc((u_int)(MAXIMUM(in.dbsz, cbsz) + cbsz))) == NULL ||
-           (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
-               err(1, "output buffer");
+       } else {
+               in.db = malloc(MAXIMUM(in.dbsz, cbsz) + cbsz);
+               if (in.db == NULL)
+                       err(1, "input buffer");
+               out.db = malloc(out.dbsz + cbsz);
+               if (out.db == NULL)
+                       err(1, "output buffer");
+       }
        in.dbp = in.db;
        out.dbp = out.db;
 

Reply via email to