summaryrefslogtreecommitdiffstats
path: root/lib/lzo
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lzo')
-rw-r--r--lib/lzo/Makefile2
-rw-r--r--lib/lzo/lzo1x_compress.c102
-rw-r--r--lib/lzo/lzo1x_compress_safe.c18
3 files changed, 96 insertions, 26 deletions
diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
index 2f58fafbbddd..fc7b2b7ef4b2 100644
--- a/lib/lzo/Makefile
+++ b/lib/lzo/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-lzo_compress-objs := lzo1x_compress.o
+lzo_compress-objs := lzo1x_compress.o lzo1x_compress_safe.o
lzo_decompress-objs := lzo1x_decompress_safe.o
obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o
diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c
index 47d6d43ea957..7b10ca86a893 100644
--- a/lib/lzo/lzo1x_compress.c
+++ b/lib/lzo/lzo1x_compress.c
@@ -18,11 +18,22 @@
#include <linux/lzo.h>
#include "lzodefs.h"
-static noinline size_t
-lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
- unsigned char *out, size_t *out_len,
- size_t ti, void *wrkmem, signed char *state_offset,
- const unsigned char bitstream_version)
+#undef LZO_UNSAFE
+
+#ifndef LZO_SAFE
+#define LZO_UNSAFE 1
+#define LZO_SAFE(name) name
+#define HAVE_OP(x) 1
+#endif
+
+#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
+
+static noinline int
+LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len,
+ unsigned char **out, unsigned char *op_end,
+ size_t *tp, void *wrkmem,
+ signed char *state_offset,
+ const unsigned char bitstream_version)
{
const unsigned char *ip;
unsigned char *op;
@@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
const unsigned char * const ip_end = in + in_len - 20;
const unsigned char *ii;
lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
+ size_t ti = *tp;
- op = out;
+ op = *out;
ip = in;
ii = ip;
ip += ti < 4 ? 4 - ti : 0;
@@ -116,25 +128,32 @@ next:
if (t != 0) {
if (t <= 3) {
op[*state_offset] |= t;
+ NEED_OP(4);
COPY4(op, ii);
op += t;
} else if (t <= 16) {
+ NEED_OP(17);
*op++ = (t - 3);
COPY8(op, ii);
COPY8(op + 8, ii + 8);
op += t;
} else {
if (t <= 18) {
+ NEED_OP(1);
*op++ = (t - 3);
} else {
size_t tt = t - 18;
+ NEED_OP(1);
*op++ = 0;
while (unlikely(tt > 255)) {
tt -= 255;
+ NEED_OP(1);
*op++ = 0;
}
+ NEED_OP(1);
*op++ = tt;
}
+ NEED_OP(t);
do {
COPY8(op, ii);
COPY8(op + 8, ii + 8);
@@ -151,6 +170,7 @@ next:
if (unlikely(run_length)) {
ip += run_length;
run_length -= MIN_ZERO_RUN_LENGTH;
+ NEED_OP(4);
put_unaligned_le32((run_length << 21) | 0xfffc18
| (run_length & 0x7), op);
op += 4;
@@ -243,10 +263,12 @@ m_len_done:
ip += m_len;
if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
m_off -= 1;
+ NEED_OP(2);
*op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
*op++ = (m_off >> 3);
} else if (m_off <= M3_MAX_OFFSET) {
m_off -= 1;
+ NEED_OP(1);
if (m_len <= M3_MAX_LEN)
*op++ = (M3_MARKER | (m_len - 2));
else {
@@ -254,14 +276,18 @@ m_len_done:
*op++ = M3_MARKER | 0;
while (unlikely(m_len > 255)) {
m_len -= 255;
+ NEED_OP(1);
*op++ = 0;
}
+ NEED_OP(1);
*op++ = (m_len);
}
+ NEED_OP(2);
*op++ = (m_off << 2);
*op++ = (m_off >> 6);
} else {
m_off -= 0x4000;
+ NEED_OP(1);
if (m_len <= M4_MAX_LEN)
*op++ = (M4_MARKER | ((m_off >> 11) & 8)
| (m_len - 2));
@@ -282,11 +308,14 @@ m_len_done:
m_len -= M4_MAX_LEN;
*op++ = (M4_MARKER | ((m_off >> 11) & 8));
while (unlikely(m_len > 255)) {
+ NEED_OP(1);
m_len -= 255;
*op++ = 0;
}
+ NEED_OP(1);
*op++ = (m_len);
}
+ NEED_OP(2);
*op++ = (m_off << 2);
*op++ = (m_off >> 6);
}
@@ -295,14 +324,20 @@ finished_writing_instruction:
ii = ip;
goto next;
}
- *out_len = op - out;
- return in_end - (ii - ti);
+ *out = op;
+ *tp = in_end - (ii - ti);
+ return LZO_E_OK;
+
+output_overrun:
+ return LZO_E_OUTPUT_OVERRUN;
}
-static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
- unsigned char *out, size_t *out_len,
- void *wrkmem, const unsigned char bitstream_version)
+static int LZO_SAFE(lzogeneric1x_1_compress)(
+ const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len,
+ void *wrkmem, const unsigned char bitstream_version)
{
+ unsigned char * const op_end = out + *out_len;
const unsigned char *ip = in;
unsigned char *op = out;
unsigned char *data_start;
@@ -326,14 +361,18 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
while (l > 20) {
size_t ll = min_t(size_t, l, m4_max_offset + 1);
uintptr_t ll_end = (uintptr_t) ip + ll;
+ int err;
+
if ((ll_end + ((t + ll) >> 5)) <= ll_end)
break;
BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
- t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem,
- &state_offset, bitstream_version);
+ err = LZO_SAFE(lzo1x_1_do_compress)(
+ ip, ll, &op, op_end, &t, wrkmem,
+ &state_offset, bitstream_version);
+ if (err != LZO_E_OK)
+ return err;
ip += ll;
- op += *out_len;
l -= ll;
}
t += l;
@@ -342,20 +381,26 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
const unsigned char *ii = in + in_len - t;
if (op == data_start && t <= 238) {
+ NEED_OP(1);
*op++ = (17 + t);
} else if (t <= 3) {
op[state_offset] |= t;
} else if (t <= 18) {
+ NEED_OP(1);
*op++ = (t - 3);
} else {
size_t tt = t - 18;
+ NEED_OP(1);
*op++ = 0;
while (tt > 255) {
tt -= 255;
+ NEED_OP(1);
*op++ = 0;
}
+ NEED_OP(1);
*op++ = tt;
}
+ NEED_OP(t);
if (t >= 16) do {
COPY8(op, ii);
COPY8(op + 8, ii + 8);
@@ -368,31 +413,38 @@ static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
} while (--t > 0);
}
+ NEED_OP(3);
*op++ = M4_MARKER | 1;
*op++ = 0;
*op++ = 0;
*out_len = op - out;
return LZO_E_OK;
+
+output_overrun:
+ return LZO_E_OUTPUT_OVERRUN;
}
-int lzo1x_1_compress(const unsigned char *in, size_t in_len,
- unsigned char *out, size_t *out_len,
- void *wrkmem)
+int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len,
+ void *wrkmem)
{
- return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0);
+ return LZO_SAFE(lzogeneric1x_1_compress)(
+ in, in_len, out, out_len, wrkmem, 0);
}
-int lzorle1x_1_compress(const unsigned char *in, size_t in_len,
- unsigned char *out, size_t *out_len,
- void *wrkmem)
+int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len,
+ unsigned char *out, size_t *out_len,
+ void *wrkmem)
{
- return lzogeneric1x_1_compress(in, in_len, out, out_len,
- wrkmem, LZO_VERSION);
+ return LZO_SAFE(lzogeneric1x_1_compress)(
+ in, in_len, out, out_len, wrkmem, LZO_VERSION);
}
-EXPORT_SYMBOL_GPL(lzo1x_1_compress);
-EXPORT_SYMBOL_GPL(lzorle1x_1_compress);
+EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress));
+EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress));
+#ifndef LZO_UNSAFE
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LZO1X-1 Compressor");
+#endif
diff --git a/lib/lzo/lzo1x_compress_safe.c b/lib/lzo/lzo1x_compress_safe.c
new file mode 100644
index 000000000000..371c9f849492
--- /dev/null
+++ b/lib/lzo/lzo1x_compress_safe.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * LZO1X Compressor from LZO
+ *
+ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ * The full LZO package can be found at:
+ * http://www.oberhumer.com/opensource/lzo/
+ *
+ * Changed for Linux kernel use by:
+ * Nitin Gupta <nitingupta910@gmail.com>
+ * Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO_SAFE(name) name##_safe
+#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
+
+#include "lzo1x_compress.c"