Message ID | 1403887219-5009-1-git-send-email-luis.henriques@canonical.com |
---|---|
State | New |
Headers | show |
On 06/27/2014 09:40 AM, Luis Henriques wrote: > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > > The lzo decompressor can, if given some really crazy data, possibly > overrun some variable types. Modify the checking logic to properly > detect overruns before they happen. > > Reported-by: "Don A. Bailey" <donb@securitymouse.com> > Tested-by: "Don A. Bailey" <donb@securitymouse.com> > Cc: stable <stable@vger.kernel.org> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > (cherry picked from commit 206a81c18401c0cde6e579164f752c4b147324ce) > CVE-2014-4608 > Signed-off-by: Luis Henriques <luis.henriques@canonical.com> > --- > lib/lzo/lzo1x_decompress_safe.c | 62 +++++++++++++++++++++++++++-------------- > 1 file changed, 41 insertions(+), 21 deletions(-) > > diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c > index 569985d522d5..8563081e8da3 100644 > --- a/lib/lzo/lzo1x_decompress_safe.c > +++ b/lib/lzo/lzo1x_decompress_safe.c > @@ -19,11 +19,31 @@ > #include <linux/lzo.h> > #include "lzodefs.h" > > -#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) > -#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) > -#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun > -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun > -#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun > +#define HAVE_IP(t, x) \ > + (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ > + (((t + x) >= t) && ((t + x) >= x))) > + > +#define HAVE_OP(t, x) \ > + (((size_t)(op_end - op) >= (size_t)(t + x)) && \ > + (((t + x) >= t) && ((t + x) >= x))) > + > +#define NEED_IP(t, x) \ > + do { \ > + if (!HAVE_IP(t, x)) \ > + goto input_overrun; \ > + } while (0) > + > +#define NEED_OP(t, x) \ > + do { \ > + if (!HAVE_OP(t, x)) \ > + goto output_overrun; \ > + } while (0) > + > +#define TEST_LB(m_pos) \ > + do { \ > + if ((m_pos) < out) \ > + goto lookbehind_overrun; \ > + } while (0) > > int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, > unsigned char *out, size_t *out_len) > @@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 15 + *ip++; > } > t += 3; > copy_literal_run: > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > - if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { > + if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { > const unsigned char *ie = ip + t; > unsigned char *oe = op + t; > do { > @@ -81,8 +101,8 @@ copy_literal_run: > } else > #endif > { > - NEED_OP(t); > - NEED_IP(t + 3); > + NEED_OP(t, 0); > + NEED_IP(t, 3); > do { > *op++ = *ip++; > } while (--t > 0); > @@ -95,7 +115,7 @@ copy_literal_run: > m_pos -= t >> 2; > m_pos -= *ip++ << 2; > TEST_LB(m_pos); > - NEED_OP(2); > + NEED_OP(2, 0); > op[0] = m_pos[0]; > op[1] = m_pos[1]; > op += 2; > @@ -119,10 +139,10 @@ copy_literal_run: > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 31 + *ip++; > - NEED_IP(2); > + NEED_IP(2, 0); > } > m_pos = op - 1; > next = get_unaligned_le16(ip); > @@ -137,10 +157,10 @@ copy_literal_run: > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 7 + *ip++; > - NEED_IP(2); > + NEED_IP(2, 0); > } > next = get_unaligned_le16(ip); > ip += 2; > @@ -154,7 +174,7 @@ copy_literal_run: > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > if (op - m_pos >= 8) { > unsigned char *oe = op + t; > - if (likely(HAVE_OP(t + 15))) { > + if (likely(HAVE_OP(t, 15))) { > do { > COPY8(op, m_pos); > op += 8; > @@ -164,7 +184,7 @@ copy_literal_run: > m_pos += 8; > } while (op < oe); > op = oe; > - if (HAVE_IP(6)) { > + if (HAVE_IP(6, 0)) { > state = next; > COPY4(op, ip); > op += next; > @@ -172,7 +192,7 @@ copy_literal_run: > continue; > } > } else { > - NEED_OP(t); > + NEED_OP(t, 0); > do { > *op++ = *m_pos++; > } while (op < oe); > @@ -181,7 +201,7 @@ copy_literal_run: > #endif > { > unsigned char *oe = op + t; > - NEED_OP(t); > + NEED_OP(t, 0); > op[0] = m_pos[0]; > op[1] = m_pos[1]; > op += 2; > @@ -194,15 +214,15 @@ match_next: > state = next; > t = next; > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > - if (likely(HAVE_IP(6) && HAVE_OP(4))) { > + if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { > COPY4(op, ip); > op += t; > ip += t; > } else > #endif > { > - NEED_IP(t + 3); > - NEED_OP(t); > + NEED_IP(t, 3); > + NEED_OP(t, 0); > while (t > 0) { > *op++ = *ip++; > t--; >
On 27.06.2014 18:40, Luis Henriques wrote: > From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > > The lzo decompressor can, if given some really crazy data, possibly > overrun some variable types. Modify the checking logic to properly > detect overruns before they happen. > > Reported-by: "Don A. Bailey" <donb@securitymouse.com> > Tested-by: "Don A. Bailey" <donb@securitymouse.com> > Cc: stable <stable@vger.kernel.org> > Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > (cherry picked from commit 206a81c18401c0cde6e579164f752c4b147324ce) > CVE-2014-4608 > Signed-off-by: Luis Henriques <luis.henriques@canonical.com> > --- > lib/lzo/lzo1x_decompress_safe.c | 62 +++++++++++++++++++++++++++-------------- > 1 file changed, 41 insertions(+), 21 deletions(-) > > diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c > index 569985d522d5..8563081e8da3 100644 > --- a/lib/lzo/lzo1x_decompress_safe.c > +++ b/lib/lzo/lzo1x_decompress_safe.c > @@ -19,11 +19,31 @@ > #include <linux/lzo.h> > #include "lzodefs.h" > > -#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) > -#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) > -#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun > -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun > -#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun > +#define HAVE_IP(t, x) \ > + (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ > + (((t + x) >= t) && ((t + x) >= x))) > + > +#define HAVE_OP(t, x) \ > + (((size_t)(op_end - op) >= (size_t)(t + x)) && \ > + (((t + x) >= t) && ((t + x) >= x))) > + > +#define NEED_IP(t, x) \ > + do { \ > + if (!HAVE_IP(t, x)) \ > + goto input_overrun; \ > + } while (0) > + > +#define NEED_OP(t, x) \ > + do { \ > + if (!HAVE_OP(t, x)) \ > + goto output_overrun; \ > + } while (0) > + > +#define TEST_LB(m_pos) \ > + do { \ > + if ((m_pos) < out) \ > + goto lookbehind_overrun; \ > + } while (0) > > int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, > unsigned char *out, size_t *out_len) > @@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 15 + *ip++; > } > t += 3; > copy_literal_run: > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > - if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { > + if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { > const unsigned char *ie = ip + t; > unsigned char *oe = op + t; > do { > @@ -81,8 +101,8 @@ copy_literal_run: > } else > #endif > { > - NEED_OP(t); > - NEED_IP(t + 3); > + NEED_OP(t, 0); > + NEED_IP(t, 3); > do { > *op++ = *ip++; > } while (--t > 0); > @@ -95,7 +115,7 @@ copy_literal_run: > m_pos -= t >> 2; > m_pos -= *ip++ << 2; > TEST_LB(m_pos); > - NEED_OP(2); > + NEED_OP(2, 0); > op[0] = m_pos[0]; > op[1] = m_pos[1]; > op += 2; > @@ -119,10 +139,10 @@ copy_literal_run: > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 31 + *ip++; > - NEED_IP(2); > + NEED_IP(2, 0); > } > m_pos = op - 1; > next = get_unaligned_le16(ip); > @@ -137,10 +157,10 @@ copy_literal_run: > while (unlikely(*ip == 0)) { > t += 255; > ip++; > - NEED_IP(1); > + NEED_IP(1, 0); > } > t += 7 + *ip++; > - NEED_IP(2); > + NEED_IP(2, 0); > } > next = get_unaligned_le16(ip); > ip += 2; > @@ -154,7 +174,7 @@ copy_literal_run: > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > if (op - m_pos >= 8) { > unsigned char *oe = op + t; > - if (likely(HAVE_OP(t + 15))) { > + if (likely(HAVE_OP(t, 15))) { > do { > COPY8(op, m_pos); > op += 8; > @@ -164,7 +184,7 @@ copy_literal_run: > m_pos += 8; > } while (op < oe); > op = oe; > - if (HAVE_IP(6)) { > + if (HAVE_IP(6, 0)) { > state = next; > COPY4(op, ip); > op += next; > @@ -172,7 +192,7 @@ copy_literal_run: > continue; > } > } else { > - NEED_OP(t); > + NEED_OP(t, 0); > do { > *op++ = *m_pos++; > } while (op < oe); > @@ -181,7 +201,7 @@ copy_literal_run: > #endif > { > unsigned char *oe = op + t; > - NEED_OP(t); > + NEED_OP(t, 0); > op[0] = m_pos[0]; > op[1] = m_pos[1]; > op += 2; > @@ -194,15 +214,15 @@ match_next: > state = next; > t = next; > #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) > - if (likely(HAVE_IP(6) && HAVE_OP(4))) { > + if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { > COPY4(op, ip); > op += t; > ip += t; > } else > #endif > { > - NEED_IP(t + 3); > - NEED_OP(t); > + NEED_IP(t, 3); > + NEED_OP(t, 0); > while (t > 0) { > *op++ = *ip++; > t--; > Ok, only the safety part of the lzo changes. With the same goose bumps about gotos... -Stefan
diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c index 569985d522d5..8563081e8da3 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -19,11 +19,31 @@ #include <linux/lzo.h> #include "lzodefs.h" -#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) -#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) -#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun -#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun +#define HAVE_IP(t, x) \ + (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ + (((t + x) >= t) && ((t + x) >= x))) + +#define HAVE_OP(t, x) \ + (((size_t)(op_end - op) >= (size_t)(t + x)) && \ + (((t + x) >= t) && ((t + x) >= x))) + +#define NEED_IP(t, x) \ + do { \ + if (!HAVE_IP(t, x)) \ + goto input_overrun; \ + } while (0) + +#define NEED_OP(t, x) \ + do { \ + if (!HAVE_OP(t, x)) \ + goto output_overrun; \ + } while (0) + +#define TEST_LB(m_pos) \ + do { \ + if ((m_pos) < out) \ + goto lookbehind_overrun; \ + } while (0) int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len) @@ -58,14 +78,14 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, while (unlikely(*ip == 0)) { t += 255; ip++; - NEED_IP(1); + NEED_IP(1, 0); } t += 15 + *ip++; } t += 3; copy_literal_run: #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { + if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { const unsigned char *ie = ip + t; unsigned char *oe = op + t; do { @@ -81,8 +101,8 @@ copy_literal_run: } else #endif { - NEED_OP(t); - NEED_IP(t + 3); + NEED_OP(t, 0); + NEED_IP(t, 3); do { *op++ = *ip++; } while (--t > 0); @@ -95,7 +115,7 @@ copy_literal_run: m_pos -= t >> 2; m_pos -= *ip++ << 2; TEST_LB(m_pos); - NEED_OP(2); + NEED_OP(2, 0); op[0] = m_pos[0]; op[1] = m_pos[1]; op += 2; @@ -119,10 +139,10 @@ copy_literal_run: while (unlikely(*ip == 0)) { t += 255; ip++; - NEED_IP(1); + NEED_IP(1, 0); } t += 31 + *ip++; - NEED_IP(2); + NEED_IP(2, 0); } m_pos = op - 1; next = get_unaligned_le16(ip); @@ -137,10 +157,10 @@ copy_literal_run: while (unlikely(*ip == 0)) { t += 255; ip++; - NEED_IP(1); + NEED_IP(1, 0); } t += 7 + *ip++; - NEED_IP(2); + NEED_IP(2, 0); } next = get_unaligned_le16(ip); ip += 2; @@ -154,7 +174,7 @@ copy_literal_run: #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) if (op - m_pos >= 8) { unsigned char *oe = op + t; - if (likely(HAVE_OP(t + 15))) { + if (likely(HAVE_OP(t, 15))) { do { COPY8(op, m_pos); op += 8; @@ -164,7 +184,7 @@ copy_literal_run: m_pos += 8; } while (op < oe); op = oe; - if (HAVE_IP(6)) { + if (HAVE_IP(6, 0)) { state = next; COPY4(op, ip); op += next; @@ -172,7 +192,7 @@ copy_literal_run: continue; } } else { - NEED_OP(t); + NEED_OP(t, 0); do { *op++ = *m_pos++; } while (op < oe); @@ -181,7 +201,7 @@ copy_literal_run: #endif { unsigned char *oe = op + t; - NEED_OP(t); + NEED_OP(t, 0); op[0] = m_pos[0]; op[1] = m_pos[1]; op += 2; @@ -194,15 +214,15 @@ match_next: state = next; t = next; #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(6) && HAVE_OP(4))) { + if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { COPY4(op, ip); op += t; ip += t; } else #endif { - NEED_IP(t + 3); - NEED_OP(t); + NEED_IP(t, 3); + NEED_OP(t, 0); while (t > 0) { *op++ = *ip++; t--;