On Wed, Aug 29, 2018 at 10:58:55PM +0200, Jann Horn wrote: > If `cmd` is in the range [0x01,0x7f] and `cmd > top-data`, the > `memcpy(out, data, cmd)` can copy out-of-bounds data from after `delta_buf` > into `dst_buf`. > > This is not an exploitable bug because triggering the bug increments the > `data` pointer beyond `top`, causing the `data != top` sanity check after > the loop to trigger and discard the destination buffer - which means that > the result of the out-of-bounds read is never used for anything. > > Also, directly jump into the error handler instead of just breaking out of > the loop - otherwise, data corruption would be silently ignored if the > delta buffer ends with a command and the destination buffer is already > full. Nice catch. The patch looks good to me, but just to lay out my thought process looking for other related problems: We have two types of instructions: 1. Take N bytes from position P within the source. 2. Take the next N bytes from the delta stream. In both cases we need to check that: a. We have enough space in the destination buffer. b. We have enough source bytes. So this: > diff --git a/patch-delta.c b/patch-delta.c > index 56e0a5ede..283fb4b75 100644 > --- a/patch-delta.c > +++ b/patch-delta.c > @@ -51,13 +51,13 @@ void *patch_delta(const void *src_buf, unsigned long src_size, > if (unsigned_add_overflows(cp_off, cp_size) || > cp_off + cp_size > src_size || > cp_size > size) > - break; > + goto bad_length; > memcpy(out, (char *) src_buf + cp_off, cp_size); Covers 1a (cp_size > size) and 1b (cp_off + cp_size > src_size), plus the obvious overflow possibility. And then here: > } else if (cmd) { > - if (cmd > size) > - break; > + if (cmd > size || cmd > top - data) > + goto bad_length; > memcpy(out, data, cmd); We had previously dealt with 2a (cmd > size), but failed to handle 2b, which you've added. We don't need to deal with over/underflow here, because our subtraction is on pointers to the same buffer. > @@ -75,6 +75,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size, > > /* sanity check */ > if (data != top || size != 0) { > + bad_length: > error("delta replay has gone wild"); > bad: > free(dst_buf); And I agree that jumping straight here is a good idea. Overall, very nicely done. -Peff