Skip to content
This repository has been archived by the owner on Sep 18, 2022. It is now read-only.

Commit

Permalink
lzo: properly check for overruns
Browse files Browse the repository at this point in the history
commit 206a81c upstream.

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" <[email protected]>
Tested-by: "Don A. Bailey" <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
gregkh committed Jun 26, 2014
1 parent 39085c8 commit dc687f5
Showing 1 changed file with 41 additions and 21 deletions.
62 changes: 41 additions & 21 deletions lib/lzo/lzo1x_decompress_safe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand All @@ -81,8 +101,8 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
} else
#endif
{
NEED_OP(t);
NEED_IP(t + 3);
NEED_OP(t, 0);
NEED_IP(t, 3);
do {
*op++ = *ip++;
} while (--t > 0);
Expand All @@ -95,7 +115,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
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;
Expand All @@ -119,10 +139,10 @@ 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 += 31 + *ip++;
NEED_IP(2);
NEED_IP(2, 0);
}
m_pos = op - 1;
next = get_unaligned_le16(ip);
Expand All @@ -137,10 +157,10 @@ 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 += 7 + *ip++;
NEED_IP(2);
NEED_IP(2, 0);
}
next = get_unaligned_le16(ip);
ip += 2;
Expand All @@ -154,7 +174,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
#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;
Expand All @@ -164,15 +184,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
m_pos += 8;
} while (op < oe);
op = oe;
if (HAVE_IP(6)) {
if (HAVE_IP(6, 0)) {
state = next;
COPY4(op, ip);
op += next;
ip += next;
continue;
}
} else {
NEED_OP(t);
NEED_OP(t, 0);
do {
*op++ = *m_pos++;
} while (op < oe);
Expand All @@ -181,7 +201,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
#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;
Expand All @@ -194,15 +214,15 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
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--;
Expand Down

0 comments on commit dc687f5

Please sign in to comment.