|
|
Message-ID: <20251229175322.DTpHn3Fz@steffen%sdaoden.eu>
Date: Mon, 29 Dec 2025 18:53:22 +0100
From: Steffen Nurpmeso <steffen@...oden.eu>
To: oss-security@...ts.openwall.com
Subject: BSDiff (bspatch): remotely triggerable out-of-bound memory
access
Hello.
The BSDiff (binary difference patch) algorithm is in use in
original or modified form in several projects / products.
The patch data stores control data as (tuples of three) signed
integers (each).
There were bug reports a.k.a. CVEs in the past that covered the
first two entries of each tuple (length in octets/bytes to copy
from the differential data / the extra data block, respectively),
but not the third, which is a "relative seek [in data source]"
location to apply after the copies have taken place.
When i forked Colin Percival's bsdiff he pointed me to the FreeBSD
implementation as the "master copy" due to integrated bug fixes
(his original tarball was not accessible by then even), so i point
to that here via
https://github.com/freebsd/freebsd-src/blob/main/usr.bin/bsdiff/bspatch/bspatch.c
We see "oldpos" being initialized to 0 before the loop starts at
line #236, we then later see
/* Add old data to diff string */
for (i = 0; i < ctrl[0]; i++)
if (add_off_t(oldpos, i) < oldsize)
new[newpos + i] += old[oldpos + i];
...
oldpos = add_off_t(oldpos, ctrl[0]);
and
oldpos = add_off_t(oldpos, ctrl[2]);
The add_off_t() was introduced to catch integer overflows etc, it
effectively boils down to
#define ckd_add(R, A, B) __builtin_add_overflow((A), (B), (R))
As can be seen, an attacker who controls the patch just has to
"choose ctrl[2] in a way that causes oldpos to go negative enough"
in order to cause a negative memory in "old[oldpos+i]" above.
My bsdipa clone does
j = ctrl[2];
if(j != 0){
if(!a_bspatch_check_add(aftpos, j))
goto jleave;
aftpos += j;
if(aftpos < 0)
goto jleave;
}
ie it effectively adds an additional <0 check.
This was reported to FreeBSD back on January 30th[1].
I actually did not really know a.k.a. looked how many forks there
are etc, but just recently i did and half-hearted opened an issue
for [2] (the project seems pretty much dead).
[1] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=284472
[2] https://github.com/mendsley/bsdiff
While here, there is another "minor problem". The original BSDiff
algorithm can generate control tuples which do not produce any
data, but only contain seek instructions. The number of these is
unlimited. By collapsing such "seek-only" instructions to the
former control chunk all control tuples (but the first, hm) must
contain copy instructions, which allows for a control block bound
a.k.a. size check only by reading the "file format header".
To be remarked all data is bzip2 compressed, which allows for, say
(BSDiff is always 64-bit)
perl -e '{$i=0;while($i<24*1000000){print "\x0";++$i;}}' |
bzip2 -vzc > .Y.bz2
(stdin): 480000.000:1, 0.000 bits/byte, 100.00% saved, 24000000 in, 50 out.
which is possibly not a "DoS", but still a bit ugly.
The mitigation for that is no earlier but in S-bsdipa v0.9.0.
(Which uses a different patch format per se, etc etc.)
Ciao and greetings from Germany,
P.S.: (no "CVE doings" by me, i post to oss-security per email).
--steffen
|
|Der Kragenbaer, The moon bear,
|der holt sich munter he cheerfully and one by one
|einen nach dem anderen runter wa.ks himself off
|(By Robert Gernhardt)
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.