From f3e1b11a9293f6846425b2ea287129c3877c4e71 Mon Sep 17 00:00:00 2001 From: Grzegorz Antoniak Date: Sat, 4 May 2019 06:54:07 +0200 Subject: [PATCH] RAR5 reader: fix integer overflow This commit fixes an integer overflow triggering on invalid files during decompression. Also added a unit test. Should fix OSSFuzz issue #14555. --- libarchive/archive_read_support_format_rar5.c | 8 ++++++++ libarchive/test/test_read_format_rar5.c | 17 ++++++++++++++++- ...st_read_format_rar5_distance_overflow.rar.uu | 9 +++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 libarchive/test/test_read_format_rar5_distance_overflow.rar.uu diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c index a2e5b68e7..370c663d5 100644 --- a/libarchive/archive_read_support_format_rar5.c +++ b/libarchive/archive_read_support_format_rar5.c @@ -2811,6 +2811,14 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { return ARCHIVE_FATAL; } + if(dist >= INT_MAX - low_dist - 1) { + /* This only happens in invalid archives. */ + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Distance pointer overflow"); + return ARCHIVE_FATAL; + } + dist += low_dist; } else { /* dbits is one of [0,1,2,3] */ diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c index 5248172b0..a0f278133 100644 --- a/libarchive/test/test_read_format_rar5.c +++ b/libarchive/test/test_read_format_rar5.c @@ -1036,4 +1036,19 @@ DEFINE_TEST(test_read_format_rar5_invalid_dict_reference) assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae)); EPILOGUE(); -} \ No newline at end of file +} + +DEFINE_TEST(test_read_format_rar5_distance_overflow) +{ + uint8_t buf[16]; + + PROLOGUE("test_read_format_rar5_distance_overflow.rar"); + + assertA(0 == archive_read_next_header(a, &ae)); + /* This archive is invalid. However, processing it shouldn't cause any + * errors related to variable overflows when using -fsanitize. */ + assertA(ARCHIVE_FATAL == archive_read_data(a, buf, sizeof(buf))); + assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae)); + + EPILOGUE(); +} diff --git a/libarchive/test/test_read_format_rar5_distance_overflow.rar.uu b/libarchive/test/test_read_format_rar5_distance_overflow.rar.uu new file mode 100644 index 000000000..8fefa282e --- /dev/null +++ b/libarchive/test/test_read_format_rar5_distance_overflow.rar.uu @@ -0,0 +1,9 @@ +begin 644 test_read_format_rar5_distance_overflow.rar +M4F%R(1H'`0"-[P+2``(''/\@("`@_R4``B`@("`@("`@("`@(/__("`@("`@ +M(/\@("`@("`@((9ML63,PX"&AK%:S+?_(/\@_R#_(/\@_R#_(/\@`"``!R`@ +MR