lzo: properly check for overruns

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Original Linux commit: 206a81c18401c0cde6e579164f752c4b147324ce.

This is CVE-2014-4607 (but not a security issue in Xen, since the code
is only used for loading the Dom0 kernel and _inside_ an eventual DomU
for loading its kernel).

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
Greg Kroah-Hartman authored and Jan Beulich committed 2014-07-03 16:39:30 +02:00
1 parent 447f613c54
commit 504f70b624
1 file changed
+41 -21
+41 -21
View File
@@ -375,11 +375,31 @@ int lzo1x_1_compress(const unsigned char *in, size_t in_len,
* Richard Purdie <rpurdie@openedhand.com>
*/
#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)
@@ -414,14 +434,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 {
@@ -437,8 +457,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);
@@ -451,7 +471,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;
@@ -475,10 +495,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);
@@ -493,10 +513,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;
@@ -510,7 +530,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;
@@ -520,7 +540,7 @@ 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;
@@ -528,7 +548,7 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
continue;
}
} else {
NEED_OP(t);
NEED_OP(t, 0);
do {
*op++ = *m_pos++;
} while (op < oe);
@@ -537,7 +557,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;
@@ -550,15 +570,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--;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.