| From eafc0a02391b7b36617b36c97c4b5d6832cf5e24 Mon Sep 17 00:00:00 2001 |
| From: Guo Xuenan <guoxuenan@huawei.com> |
| Date: Fri, 8 Apr 2022 13:08:58 -0700 |
| Subject: lz4: fix LZ4_decompress_safe_partial read out of bound |
| |
| From: Guo Xuenan <guoxuenan@huawei.com> |
| |
| commit eafc0a02391b7b36617b36c97c4b5d6832cf5e24 upstream. |
| |
| When partialDecoding, it is EOF if we've either filled the output buffer |
| or can't proceed with reading an offset for following match. |
| |
| In some extreme corner cases when compressed data is suitably corrupted, |
| UAF will occur. As reported by KASAN [1], LZ4_decompress_safe_partial |
| may lead to read out of bound problem during decoding. lz4 upstream has |
| fixed it [2] and this issue has been disscussed here [3] before. |
| |
| current decompression routine was ported from lz4 v1.8.3, bumping |
| lib/lz4 to v1.9.+ is certainly a huge work to be done later, so, we'd |
| better fix it first. |
| |
| [1] https://lore.kernel.org/all/000000000000830d1205cf7f0477@google.com/ |
| [2] https://github.com/lz4/lz4/commit/c5d6f8a8be3927c0bec91bcc58667a6cfad244ad# |
| [3] https://lore.kernel.org/all/CC666AE8-4CA4-4951-B6FB-A2EFDE3AC03B@fb.com/ |
| |
| Link: https://lkml.kernel.org/r/20211111105048.2006070-1-guoxuenan@huawei.com |
| Reported-by: syzbot+63d688f1d899c588fb71@syzkaller.appspotmail.com |
| Signed-off-by: Guo Xuenan <guoxuenan@huawei.com> |
| Reviewed-by: Nick Terrell <terrelln@fb.com> |
| Acked-by: Gao Xiang <hsiangkao@linux.alibaba.com> |
| Cc: Yann Collet <cyan@fb.com> |
| Cc: Chengyang Fan <cy.fan@huawei.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| lib/lz4/lz4_decompress.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/lib/lz4/lz4_decompress.c |
| +++ b/lib/lz4/lz4_decompress.c |
| @@ -271,8 +271,12 @@ static FORCE_INLINE int LZ4_decompress_g |
| ip += length; |
| op += length; |
| |
| - /* Necessarily EOF, due to parsing restrictions */ |
| - if (!partialDecoding || (cpy == oend)) |
| + /* Necessarily EOF when !partialDecoding. |
| + * When partialDecoding, it is EOF if we've either |
| + * filled the output buffer or |
| + * can't proceed with reading an offset for following match. |
| + */ |
| + if (!partialDecoding || (cpy == oend) || (ip >= (iend - 2))) |
| break; |
| } else { |
| /* may overwrite up to WILDCOPYLENGTH beyond cpy */ |