diff options
Diffstat (limited to 'Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp')
-rw-r--r-- | Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp b/Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp index 4b8b1b4958d..26a4291392c 100644 --- a/Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp +++ b/Build/source/libs/graphite2/graphite2-src/src/Decompressor.cpp @@ -43,29 +43,32 @@ u32 read_literal(u8 const * &s, u8 const * const e, u32 l) { return l; } -bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist) +bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, + u32 & literal_len, u32 & match_len, u32 & match_dist) { u8 const token = *src++; literal_len = read_literal(src, end, token >> 4); literal = src; src += literal_len; - - if (src > end - 2 || src < literal) + + // Normal exit for end of stream, wrap arround check and parital match check. + if (src > end - sizeof(u16) || src < literal) return false; match_dist = *src++; match_dist |= *src++ << 8; - match_len = read_literal(src, end, token & 0xf); - - return src <= end-5; + match_len = read_literal(src, end, token & 0xf) + MINMATCH; + + // Malformed stream check. + return src <= end-MINCODA; } } int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size) { - if (out_size <= in_size || in_size < sizeof(unsigned long)+1) + if (out_size <= in_size || in_size < MINSRCSIZE) return -1; u8 const * src = static_cast<u8 const *>(in), @@ -74,39 +77,47 @@ int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size) u8 * dst = static_cast<u8*>(out), * const dst_end = dst + out_size; - + + // Check the in and out size hasn't wrapped around. + if (src >= src_end || dst >= dst_end) + return -1; + u32 literal_len = 0, match_len = 0, match_dist = 0; - - while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist)) + + while (read_sequence(src, src_end, literal, literal_len, match_len, + match_dist)) { if (literal_len != 0) { - // Copy in literal. At this point the last full sequence must be at - // least MINMATCH + 5 from the end of the output buffer. - if (align(literal_len) > unsigned(dst_end - dst - (MINMATCH+5)) || dst_end - dst < MINMATCH + 5) + // Copy in literal. At this point the a minimal literal + minminal + // match plus the coda (1 + 2 + 5) must be 8 bytes or more allowing + // us to remain within the src buffer for an overrun_copy on + // machines upto 64 bits. + if (align(literal_len) > out_size) return -1; dst = overrun_copy(dst, literal, literal_len); + out_size -= literal_len; } // Copy, possibly repeating, match from earlier in the // decoded output. u8 const * const pcpy = dst - match_dist; if (pcpy < static_cast<u8*>(out) - || pcpy >= dst - || match_len > unsigned(dst_end - dst - (MINMATCH+5)) - || dst_end - dst < MINMATCH + 5) + || match_len > unsigned(out_size - LASTLITERALS) + // Wrap around checks: + || out_size < LASTLITERALS || pcpy >= dst) return -1; - if (dst > pcpy+sizeof(unsigned long) - && dst + align(match_len + MINMATCH) <= dst_end) - dst = overrun_copy(dst, pcpy, match_len + MINMATCH); - else - dst = safe_copy(dst, pcpy, match_len + MINMATCH); + if (dst > pcpy+sizeof(unsigned long) + && align(match_len) <= out_size) + dst = overrun_copy(dst, pcpy, match_len); + else + dst = safe_copy(dst, pcpy, match_len); + out_size -= match_len; } - - if (literal_len > src_end - literal - || literal_len > dst_end - dst) + + if (literal > src_end - literal_len || literal_len > out_size) return -1; dst = fast_copy(dst, literal, literal_len); |