Skip to content

Commit d6398ac

Browse files
wtarreaugregkh
authored andcommitted
lzo: check for length overrun in variable length encoding.
commit 72cf901 upstream. This fix ensures that we never meet an integer overflow while adding 255 while parsing a variable length encoding. It works differently from commit 206a81c ("lzo: properly check for overruns") because instead of ensuring that we don't overrun the input, which is tricky to guarantee due to many assumptions in the code, it simply checks that the cumulated number of 255 read cannot overflow by bounding this number. The MAX_255_COUNT is the maximum number of times we can add 255 to a base count without overflowing an integer. The multiply will overflow when multiplying 255 by more than MAXINT/255. The sum will overflow earlier depending on the base count. Since the base count is taken from a u8 and a few bits, it is safe to assume that it will always be lower than or equal to 2*255, thus we can always prevent any overflow by accepting two less 255 steps. This patch also reduces the CPU overhead and actually increases performance by 1.1% compared to the initial code, while the previous fix costs 3.1% (measured on x86_64). The fix needs to be backported to all currently supported stable kernels. Reported-by: Willem Pinckaers <[email protected]> Cc: "Don A. Bailey" <[email protected]> Signed-off-by: Willy Tarreau <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 1fd3277 commit d6398ac

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

lib/lzo/lzo1x_decompress_safe.c

+37-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@
2525
#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
2626
#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
2727

28+
/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base
29+
* count without overflowing an integer. The multiply will overflow when
30+
* multiplying 255 by more than MAXINT/255. The sum will overflow earlier
31+
* depending on the base count. Since the base count is taken from a u8
32+
* and a few bits, it is safe to assume that it will always be lower than
33+
* or equal to 2*255, thus we can always prevent any overflow by accepting
34+
* two less 255 steps. See Documentation/lzo.txt for more information.
35+
*/
36+
#define MAX_255_COUNT ((((size_t)~0) / 255) - 2)
37+
2838
int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
2939
unsigned char *out, size_t *out_len)
3040
{
@@ -55,12 +65,19 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
5565
if (t < 16) {
5666
if (likely(state == 0)) {
5767
if (unlikely(t == 0)) {
68+
size_t offset;
69+
const unsigned char *ip_last = ip;
70+
5871
while (unlikely(*ip == 0)) {
59-
t += 255;
6072
ip++;
6173
NEED_IP(1);
6274
}
63-
t += 15 + *ip++;
75+
offset = ip - ip_last;
76+
if (unlikely(offset > MAX_255_COUNT))
77+
return LZO_E_ERROR;
78+
79+
offset = (offset << 8) - offset;
80+
t += offset + 15 + *ip++;
6481
}
6582
t += 3;
6683
copy_literal_run:
@@ -116,12 +133,19 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
116133
} else if (t >= 32) {
117134
t = (t & 31) + (3 - 1);
118135
if (unlikely(t == 2)) {
136+
size_t offset;
137+
const unsigned char *ip_last = ip;
138+
119139
while (unlikely(*ip == 0)) {
120-
t += 255;
121140
ip++;
122141
NEED_IP(1);
123142
}
124-
t += 31 + *ip++;
143+
offset = ip - ip_last;
144+
if (unlikely(offset > MAX_255_COUNT))
145+
return LZO_E_ERROR;
146+
147+
offset = (offset << 8) - offset;
148+
t += offset + 31 + *ip++;
125149
NEED_IP(2);
126150
}
127151
m_pos = op - 1;
@@ -134,12 +158,19 @@ int lzo1x_decompress_safe(const unsigned char *in, size_t in_len,
134158
m_pos -= (t & 8) << 11;
135159
t = (t & 7) + (3 - 1);
136160
if (unlikely(t == 2)) {
161+
size_t offset;
162+
const unsigned char *ip_last = ip;
163+
137164
while (unlikely(*ip == 0)) {
138-
t += 255;
139165
ip++;
140166
NEED_IP(1);
141167
}
142-
t += 7 + *ip++;
168+
offset = ip - ip_last;
169+
if (unlikely(offset > MAX_255_COUNT))
170+
return LZO_E_ERROR;
171+
172+
offset = (offset << 8) - offset;
173+
t += offset + 7 + *ip++;
143174
NEED_IP(2);
144175
}
145176
next = get_unaligned_le16(ip);

0 commit comments

Comments
 (0)