Version in base suite: 1.4.2dfsg1-2 Version in overlay suite: (not present) Base version: subversion_1.4.2dfsg1-2 Target version: subversion_1.4.2dfsg1-3 Base file: /org/ftp.debian.org/ftp/pool/main/s/subversion/subversion_1.4.2dfsg1-2.dsc Target file: /org/ftp.debian.org/queue/o-p-u-new/subversion_1.4.2dfsg1-3.dsc debian/patches/cve-2009-2411 | 215 ++++++++++++++++++++++++++++ subversion-1.4.2dfsg1/debian/changelog | 6 subversion-1.4.2dfsg1/debian/patches/00list | 1 3 files changed, 222 insertions(+) diff -u subversion-1.4.2dfsg1/debian/patches/00list subversion-1.4.2dfsg1/debian/patches/00list --- subversion-1.4.2dfsg1/debian/patches/00list +++ subversion-1.4.2dfsg1/debian/patches/00list @@ -22,0 +23 @@ +cve-2009-2411 diff -u subversion-1.4.2dfsg1/debian/changelog subversion-1.4.2dfsg1/debian/changelog --- subversion-1.4.2dfsg1/debian/changelog +++ subversion-1.4.2dfsg1/debian/changelog @@ -1,3 +1,9 @@ +subversion (1.4.2dfsg1-3) oldstable-security; urgency=high + + * Fix CVE-2009-2411, heap overflows in svndiff stream parsing. + + -- Peter Samuelson Wed, 05 Aug 2009 19:35:44 -0500 + subversion (1.4.2dfsg1-2) unstable; urgency=medium [ Peter Samuelson ] only in patch2: unchanged: --- subversion-1.4.2dfsg1.orig/debian/patches/cve-2009-2411 +++ subversion-1.4.2dfsg1/debian/patches/cve-2009-2411 @@ -0,0 +1,215 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## cve-2009-2411 by Hyrum Wright +## +## DP: Fix CVE-2009-2411, heap overflows in svndiff stream parsing. +## DP: Backported from 1.5.7 release. + +@DPATCH@ +Index: subversion/libsvn_delta/svndiff.c +--- a/subversion/libsvn_delta/svndiff.c ++++ b/subversion/libsvn_delta/svndiff.c +@@ -55,10 +55,23 @@ + apr_pool_t *pool; + }; + ++/* This is at least as big as the largest size of an integer that ++ encode_int can generate; it is sufficient for creating buffers for ++ it to write into. This assumes that integers are at most 64 bits, ++ and so 10 bytes (with 7 bits of information each) are sufficient to ++ represent them. */ ++#define MAX_ENCODED_INT_LEN 10 ++/* This is at least as big as the largest size for a single instruction. */ ++#define MAX_INSTRUCTION_LEN (2*MAX_ENCODED_INT_LEN+1) ++/* This is at least as big as the largest possible instructions ++ section: in theory, the instructions could be SVN_DELTA_WINDOW_SIZE ++ 1-byte copy-from-source instructions (though this is very unlikely). */ ++#define MAX_INSTRUCTION_SECTION_LEN (SVN_DELTA_WINDOW_SIZE*MAX_INSTRUCTION_LEN) + + /* Encode VAL into the buffer P using the variable-length svndiff + integer format. Return the incremented value of P after the +- encoded bytes have been written. ++ encoded bytes have been written. P must point to a buffer of size ++ at least MAX_ENCODED_INT_LEN. + + This encoding uses the high bit of each byte as a continuation bit + and the other seven bits as data bits. High-order data bits are +@@ -91,6 +104,8 @@ + n++; + } + ++ assert(n <= MAX_ENCODED_INT_LEN); ++ + /* Encode the remaining bytes; n is always the number of bytes + coming after the one we're encoding. */ + while (--n >= 0) +@@ -107,7 +122,7 @@ + static void + append_encoded_int(svn_stringbuf_t *header, svn_filesize_t val) + { +- char buf[128], *p; ++ char buf[MAX_ENCODED_INT_LEN], *p; + + p = encode_int(buf, val); + svn_stringbuf_appendbytes(header, buf, p - buf); +@@ -163,7 +178,7 @@ + svn_stringbuf_t *i1 = svn_stringbuf_create("", pool); + svn_stringbuf_t *header = svn_stringbuf_create("", pool); + const svn_string_t *newdata; +- char ibuf[128], *ip; ++ char ibuf[MAX_INSTRUCTION_LEN], *ip; + const svn_txdelta_op_t *op; + apr_size_t len; + +@@ -341,6 +356,8 @@ + const unsigned char *p, + const unsigned char *end) + { ++ if (p + MAX_ENCODED_INT_LEN < end) ++ end = p + MAX_ENCODED_INT_LEN; + /* Decode bytes until we're done. */ + *val = 0; + while (p < end) +@@ -360,6 +377,8 @@ + const unsigned char *p, + const unsigned char *end) + { ++ if (p + MAX_ENCODED_INT_LEN < end) ++ end = p + MAX_ENCODED_INT_LEN; + /* Decode bytes until we're done. */ + *val = 0; + while (p < end) +@@ -377,7 +396,7 @@ + data is not compressed. */ + + static svn_error_t * +-zlib_decode(svn_stringbuf_t *in, svn_stringbuf_t *out) ++zlib_decode(svn_stringbuf_t *in, svn_stringbuf_t *out, apr_size_t limit) + { + apr_size_t len; + char *oldplace = in->data; +@@ -385,6 +404,13 @@ + /* First thing in the string is the original length. */ + in->data = (char *)decode_size(&len, (unsigned char *)in->data, + (unsigned char *)in->data+in->len); ++ if (in->data == NULL) ++ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, NULL, ++ _("Decompression of svndiff data failed: no size")); ++ if (len > limit) ++ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, NULL, ++ _("Decompression of svndiff data failed: " ++ "size too large")); + /* We need to subtract the size of the encoded original length off the + * still remaining input length. */ + in->len -= (in->data - oldplace); +@@ -482,10 +508,10 @@ + return svn_error_createf + (SVN_ERR_SVNDIFF_INVALID_OPS, NULL, + _("Invalid diff stream: insn %d cannot be decoded"), n); +- else if (op.length <= 0) ++ else if (op.length == 0) + return svn_error_createf + (SVN_ERR_SVNDIFF_INVALID_OPS, NULL, +- _("Invalid diff stream: insn %d has non-positive length"), n); ++ _("Invalid diff stream: insn %d has length zero"), n); + else + return svn_error_createf + (SVN_ERR_SVNDIFF_INVALID_OPS, NULL, +@@ -495,7 +521,8 @@ + switch (op.action_code) + { + case svn_txdelta_source: +- if (op.length > sview_len - op.offset) ++ if (op.length > sview_len - op.offset || ++ op.offset > sview_len) + return svn_error_createf + (SVN_ERR_SVNDIFF_INVALID_OPS, NULL, + _("Invalid diff stream: " +@@ -561,11 +588,11 @@ + + instin = svn_stringbuf_ncreate((const char *)data, insend - data, pool); + instout = svn_stringbuf_create("", pool); +- SVN_ERR(zlib_decode(instin, instout)); ++ SVN_ERR(zlib_decode(instin, instout, MAX_INSTRUCTION_SECTION_LEN)); + + ndin = svn_stringbuf_ncreate((const char *)insend, newlen, pool); + ndout = svn_stringbuf_create("", pool); +- SVN_ERR(zlib_decode(ndin, ndout)); ++ SVN_ERR(zlib_decode(ndin, ndout, SVN_DELTA_WINDOW_SIZE)); + + newlen = ndout->len; + data = (unsigned char *)instout->data; +@@ -681,6 +708,14 @@ + if (p == NULL) + return SVN_NO_ERROR; + ++ if (tview_len > SVN_DELTA_WINDOW_SIZE || ++ sview_len > SVN_DELTA_WINDOW_SIZE || ++ /* for svndiff1, newlen includes the original length */ ++ newlen > SVN_DELTA_WINDOW_SIZE + MAX_ENCODED_INT_LEN || ++ inslen > MAX_INSTRUCTION_SECTION_LEN) ++ return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL, ++ _("Svndiff contains a too-large window")); ++ + /* Check for integer overflow. */ + if (sview_offset < 0 || inslen + newlen < inslen + || sview_len + tview_len < sview_len +@@ -837,6 +872,14 @@ + SVN_ERR(read_one_size(inslen, stream)); + SVN_ERR(read_one_size(newlen, stream)); + ++ if (*tview_len > SVN_DELTA_WINDOW_SIZE || ++ *sview_len > SVN_DELTA_WINDOW_SIZE || ++ /* for svndiff1, newlen includes the original length */ ++ *newlen > SVN_DELTA_WINDOW_SIZE + MAX_ENCODED_INT_LEN || ++ *inslen > MAX_INSTRUCTION_SECTION_LEN) ++ return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL, ++ _("Svndiff contains a too-large window")); ++ + /* Check for integer overflow. */ + if (*sview_offset < 0 || *inslen + *newlen < *inslen + || *sview_len + *tview_len < *sview_len +Index: subversion/libsvn_delta/text_delta.c +--- a/subversion/libsvn_delta/text_delta.c ++++ b/subversion/libsvn_delta/text_delta.c +@@ -498,7 +498,7 @@ + /* Functions for applying deltas. */ + + /* Ensure that BUF has enough space for VIEW_LEN bytes. */ +-static APR_INLINE void ++static APR_INLINE svn_error_t * + size_buffer(char **buf, apr_size_t *buf_size, + apr_size_t view_len, apr_pool_t *pool) + { +@@ -507,8 +507,13 @@ + *buf_size *= 2; + if (*buf_size < view_len) + *buf_size = view_len; ++ if (APR_ALIGN_DEFAULT(*buf_size) < *buf_size) ++ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_OPS, NULL, ++ "Diff stream resulted in invalid buffer size."); + *buf = apr_palloc(pool, *buf_size); + } ++ ++ return SVN_NO_ERROR; + } + + +@@ -609,7 +614,7 @@ + >= ab->sbuf_offset + ab->sbuf_len))); + + /* Make sure there's enough room in the target buffer. */ +- size_buffer(&ab->tbuf, &ab->tbuf_size, window->tview_len, ab->pool); ++ SVN_ERR(size_buffer(&ab->tbuf, &ab->tbuf_size, window->tview_len, ab->pool)); + + /* Prepare the source buffer for reading from the input stream. */ + if (window->sview_offset != ab->sbuf_offset +@@ -618,7 +623,8 @@ + char *old_sbuf = ab->sbuf; + + /* Make sure there's enough room. */ +- size_buffer(&ab->sbuf, &ab->sbuf_size, window->sview_len, ab->pool); ++ SVN_ERR(size_buffer(&ab->sbuf, &ab->sbuf_size, window->sview_len, ++ ab->pool)); + + /* If the existing view overlaps with the new view, copy the + * overlap to the beginning of the new buffer. */